代码改变世界

关于js中一个对象当做参数传递是按值传递还是按引用传递的个人看法

2015-04-08 21:53  那时候的我  阅读(13943)  评论(7编辑  收藏  举报

在《JavaScript高级程序设计》这本书中有这样一段话:有很多开发人员错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。换句话说,尼古拉认为当一个对象是当做参数传递时,它是按值传递的。然后他举了个例子来证明这个结论:

function setName(obj) {
  obj.name = "Nicholas";
  obj = new Object();
  obj.name = "Greg";	
}

var person = new Object();
setName(person);
alert(person.name); // "Nicholas"

他解释到:如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为"Greg"的新对象。但是,当接下来再访问person.name时,显示的值任然是"Nicholas"。这说明即使在函数内部修改了参数的值,但原始的引用任然保持不变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

从上面的例子中,尼古拉得出的结论是:当一个对象当做参数传递时,它是按值传递的。

然而,我们可以肯定的是:当一个引用类型的对象不是当做参数传递时,它是按引用传递的。

我们来看另外一个例子:

var person = new Object();
var obj = person;
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
alert(person.name); // "Nicholas"

这个例子中person对象不是当做参数传递的,但person.name的值还是"Nicholas",这和person当做参数传递的情况是一样的。可以确定的是:这个例子中对象是按引用传递的。但按照尼古拉的说法这个例子中对象也是按值传递的。 那么可以得出结论:尼古拉的说法是错的。

我们可用图来说明一下这个问题。

var person = new Object()时,可以用下面这幅图来描述变量和对象之间的关系:

var obj = person时,可以用下面这幅图来描述它们之间的关系:

obj = new Object()时,用下面的图描述它们的关系:

我们可以把Object当成一个中间人,它是联系personobj的桥梁。之所以改变obj的属性值,会影响person其实是通过Object来传递的。当obj = new Object(),这时objObject之间的关系完全断开,与new Object建立了关系。当obj.name = "Greg",此时,obj"Object"之间已没有关系,当然不会再影响"Object"

书中的例子是一样的道理:

function setName(obj) {
  obj.name = "Nicholas";
  obj = new Object();
  obj.name = "Greg";	
}

var person = new Object();
setName(person);
alert(person.name); // "Nicholas"

obj相当于setName函数中的一个局部变量,把person传给函数就相当于var obj = person。其实我们完全可以把这个例子和上面介绍的那个例子看成是等价的,所以上面的图解也适用这个例子。

上面通过例子来说明尼古拉的结论是错的,从而得出自己的结论:ECMAScript中,对象无论是不是当成参数传递,都是按引用传递的。当然这仅是我个人得出的结论,如果大家有不同的看法,非常愿意向大家学习。