首页 > JavaScript > JavaScript 传递参数是值传递?还是值传递啊?
2010三月5

JavaScript 传递参数是值传递?还是值传递啊?

本文摘自:李松峰老师 翻译的 《JavaScript 高级程序设计 第二版》

在本文开头,首先,十万以及万分肯定的说一句,JavaScript 函数传递参数时,是值传递。虽然您可能不信,因为ECMAScript 变量可能包含两种不同数据类型的值:基本数据类型,和引用数据类型。难道引用数据类型传递的时候难道也是值传递吗?答,没错。

引用类型的值是什么东西

当一个变量向另一个变量复制引用类型的值时,会将存储在栈中的值(栈中存放的值是对应堆中的引用地址)复制一份到为新变量分配的空间中。

不同的是,这个值的副本其实是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上引用同一个对象。

var user = new Object();

var admin = user;

admin.name = "xiaoxiaozi";

alert(user.name); //返回 xiaoxiaozi

该过程其实是这样的:

引用型变量的复制

引用型变量的复制

所以说,引用类型的值实际上是对其引用对象的一个指针。

传递的参数

基本类型我们不做讨论,那玩意除了值还真没别的。咱们继续来说引用类型。请看下面试例:

function setName(obj){
        obj.name = "xiaoxiaozi";
}

var person = new Object();
setName(person);

alert(person.name); // 返回 xiaoxiaozi

在向参数传递引用类型值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

ECMAScript 中,所有函数的参数都是按值来传递的。基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),引用类型值的传递和引用类型变量的复制一致(栈内存放的是指针,指向堆中同一对象)

因此在调用函数setName()时,person 被复制给了 obj ,因此在函数内部 obj 与 person 引用的是同一个对象,或者说是对同一个对象的引用。所以在给 obj 引用对象加上 name 属性时,person 引用的对象也有了 name 属性,因为虽然 obj 与 person 不同,但是二者引用的对象是同一个。

但是,千万不要认为,在局部作用域中修改的对象会在全局作用域中反映出来就说参数是按引用传递的。为了证明是值传递,让我们再来看如下例子:

function setName(obj){
     obj.name = "xiaoxiaozi";
     obj = new Object();
     obj.name = "admin";
}
var person = new Object();
setName(person);
alert(person.name); // 结果依旧是 xiaoxiaozi

在调用 setName() 函数初时,obj 与 person 引用的是同一对象,所以首次的 name 属性赋值会对 person 有所影响。但是当 obj 被重新定义时,其引用的对象已经与 person 不同,所以后面设置的 name 属性,不会对 person 引用的对象有任何影响。

感觉上面的这个例子非常好,大家可以仔细体会一下,我也是看到了这个例子才决定从文中摘抄(貌似没有摘,就是抄)的。

文章作者:simaopig
本文地址:http://www.xiaoxiaozi.com/2010/03/05/1719/
版权所有 © 转载时必须以链接形式注明作者和原始出处!

9 Responses to “JavaScript 传递参数是值传递?还是值传递啊?”

  1. #1 LAONB 回复 | 引用 Post:2010-03-06 09:07

    听说指针很强大,可以直接跟硬件对话。 :oops:

    [回复]

  2. #2 simaopig 回复 | 引用 Post:2010-03-06 10:26

    @LAONB
    貌似你说的是C的指针。。我说的这个不一样滴。嘻嘻。。

    [回复]

  3. #3 LAONB 回复 | 引用 Post:2010-03-06 17:33

    @simaopig
    没错,我还以为这东西也是通用的,看来理解错误了。

    [回复]

  4. #4 GuoJing 回复 | 引用 Post:2010-03-11 09:33

    @LAONB
    其实这个东西是通用的,当然你说的c不通用是因为c不算面向对象,在面向对象的开发语言中,c++/java/c#都有值类型和引用类型,值类型都是新建存储空间,而引用类型都是指向同一个指针地址,基本上都是一样的,如果要深入研究就要看函数在调用的时候参数是如何压栈的了,这个就更复杂了。

    不过基本上都是对,这个很基础,好的程序员需要具备这样的知识。感谢lz再次写这样一篇文章,很不错。支持。

    [回复]

  5. #5 zhenn 回复 | 引用 Post:2010-03-31 16:57

    恩,没错,是这样滴!

    [回复]

  6. #6 赫尔墨斯 回复 | 引用 Post:2010-10-14 13:26

    // 测试类
    function classA()
    {
    this.name = ‘jimmy’;
    }

    // 释放对象
    function nullObj(obj)
    {
    obj.null;
    }

    var obj = new classA();
    nullObj(obj);

    请问这个对象是否被析构了?

    [回复]

  7. #7 simaopig 回复 | 引用 Post:2010-10-14 13:29

    @赫尔墨斯
    应该是obj=null吧?

    [回复]

  8. #8 simaopig 回复 | 引用 Post:2011-05-11 21:16

    今天又重新翻到了这篇文章,上面的兄弟。这个没有被析构。原因是obj被重新赋值为一个新的值,null。但是obj,全局的这个指针仍然是指向到A的那个实例上。

    alert(obj.name) 依旧有值。

    [回复]

  9. #9 Rain.Zhai 回复 | 引用 Post:2011-06-30 18:56

    Ecma里面讲到:The internal Reference type is not a language data type. It is defined by this specification purely for
    expository purposes.既然不是数据类型,又哪来指针一说呢?求教

    [回复]

发表评论

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)