js中参数传递为何一定是按值传递,有些疑惑,如下是一些理解。函数
js高级程序设计(第三版)的第四章,代表了基本数据类型(Undefined、Null、Boolean、Number、String)是按值访问的,对象是按引用访问的。spa
首先,看下引用类型变量是怎样的(obj一、obj2都是对象类型):设计
var obj1 = new Object(); var obj2 = obj1;
简单来讲,obj一、obj2都是变量,他们分别有一个指针,各自指向各自的栈内存,而后栈内存中存放有堆内存地址和一些别的数据,那么就又有第二个指针根据栈内存中存放的地址指向堆内存,堆内存中存放的是同一个的对象(由于obj1和obj2栈内存中的地址是相同的)。指针
注意到书中原话:code
当从一个变量向另外一个变量复制引用类型的值时,一样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不一样的是,这个值的副本其实是一个指针,而这个指针指向存储在堆中的一个对象。复制操做结束后,两个变量实际上将引用同一个对象。所以,改变其中一个变量,就会影响另外一个变量。
而后,实验代码以下:对象
var t1 = new Object(); var t2 = t1; t2.name ="t1"; t2 = new Object(); //本质为t2的指针指向了一个新空间 console.log(t1.name); //输出t1 console.log(t2.name); //输出undefined
分析:ip
var t2 = t1;
这行代码实质是把t1栈内存中的数据复制在t2的栈内存中,栈内存中存放的堆内存地址就是同样的,于是指向了同一个堆内存地址,即指向同一个对象。内存
t2 = new Object();
这行代码就是把t2在栈内存中存放的地址改变了,变成了一个此刻不在使用的地址,而后t2的指针指向了这个新地址,因此以后t1和t2无关了。it
能够看出,书中写的 复制操做结束后,两个变量实际上将引用同一个对象。 指两个变量是两个独立的变量,惟独在于他们各自的对象都是在同一个堆内存空间的。我通俗理解为:t1和t2两个变量自己是按值访问的,t1和t2指向的对象是按引用访问的,但实际上定义变量,天然是为了操做变量指向的对象。io
下面是对于函数参数传递中的一些理解:
先看一下,让人误觉得参数是引用传递的代码:
var t1 = new Object(); function change(obj){ obj.name = "lalala"; } change(t1); console.log(t1.name); //输出了lalala
结果是外部的t1多了一个属性name,缘由就在于确实是参数传递,把t1按值传递给了obj,操做他们各自属性的时候,属性仍然是按引用传递的,咱们传的参数又不是t1的属性。
强调一下,我上面说t1的属性,是不正确的说法,严格来讲,不是t1多了一个属性,也不是t1的属性,而是t1指向的对象多了一个属性,或者说那是t1指向的对象的属性,t1只是一个变量罢了。
再看下面代码:
var t1 = new Object(); function change(obj){ obj.name = "t1"; obj = new Object(); obj.name = "new t1"; } change(t1); console.log(t1.name); //输出t1
输出结果,t1.name仍然是‘‘t1’’,再进行obj = new Object()时候,由于栈内存中数据的改变,这里的obj最终指向的对象不是t1指向的对象了,就函数内部再也操做不到t1一开始指向的对象了,相似于下面代码中t2的从新声明。
var t1 = new Object(); var t2 = t1; t2.name ="t1"; t2 = new Object(); console.log(t1.name); //输出t1 console.log(t2.name); //输出undefined
结论:函数的参数传递是按值传递的,但对于参数是引用类型变量,该变量指向的对象的属性(就是t1.name之类的)是按引用访问的,所以改变对象的属性会反映在外部对象上;但变量自己按值传递了,所以改变内部变量(就只改变t一、t2),外部变量不会有改变。就是实际上没有把堆内存中的对象做为函数参数。