关于Javascript中参数的传递到底是按值传递还是按引用传递,这个问题再此之前一直没有想过,话说javascript中有两种变量类型:基本类型和引用类型,基本类型包括:Number
、String
、Undefined
、Null
、Boolean
这五种,而引用类型就是Object,根据之前在代码上的经验以及对javascript这门松散类型的语言的认识,以为在参数的传递中,传什么类型的值就按什么类型传递,比如传基本类型的变量,则参数是按照值进行传递,而传引用类型的变量的时候,则是按照引用传递。
昨晚在看《Javascript高级程序设计》的时候,才知道我之前的这种看法是错误的,下面是书中引用片段:
ECMAScript中所有的函数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一变量一样。基本类型的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。有不少开发人员在这一点上会感到困惑,因为访问变量有按值和按引用两种方式,而参数只能按值传递。
function setName(obj){
obj.name = 'Nicholas';
}
var person = new Object();
setName(person);
alert(person.name); //'Nicholas'
以上代码创建一个对象,并将其保存在了变量person中。然后,这个对象 被传递到setName()函数中之后就被复制给了obj。在这个函数内部,obj和person都引用的是同一个对象。换句话说,即使这个对象是按值传递的,obj也会按引用来访问同一个对象。于是,当在函数内部为obj添加name属性后,函数外部的person也将有所反映;因为person指向的对象在堆内存中只有一个,而且是全局对象。有很多开发人员错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。为了证明对象时按值传递的,我们在看一看下面这个经过修改的例子:
function setName(obj){
obj.name = 'Nicholas';
obj = new Object();
obj.name = 'Greg';
}
var person = new Object();
setName(person);
alert(person.name); //'Nicholas'
这个例子与前一个例子的唯一区别,就是setName()函数中添加了两行代码:一行代码为obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值得name属性。在把person传递给setName()后,其name属性被设置为’Nicholas’。然后,又将一新对象赋给变量obj,同时将其name属性设置为’Greg’。如果person是按引用传递的,那么person就会自动修改为指向其namne属性值为’Greg’的对象。但是,当接下在访问person.name时显示的仍然是’Nicholas’。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
可以把ECMAScript函数的参数想象成局部变量。
犀利,![[高兴]](https://sobird.me/wp-content/themes/junior2011/smilies/Happy.png)
CrossYou,按值传递这种说法是不是有点怪异呢?对象是分配在堆上的,它的值是多少?调用时传递对象进去时,如果不知道其内存地址,怎样对对象的属性进行修改呢?应该是函数作用域内,如果对形参重新进行其对象的生成,也就是改变其内存地址的话,会保留其真正作为实参传递进来的那个对象的状态吧。
我的理解~ :-D
对象是引用类型的,在变量里存的是这个对象的指针,这个指向对象的指针存在于栈内存上,函数传递的是这个对象的指针。
《JavaScript高级程序设计(第2版)》第61页、62页 有说明,可以看下。