最近在读《javascript高级程序设计》时碰到了js传递方式的问题,花费了些时间,不过总算明白了。javascript
数据类型java
在 javascript 中数据类型能够分为两类:函数
变量的复制spa
众所周知,js中变量的基本类型和引用类型保存方式是不一样的,这也就致使变量复制时也就不一样了。若是从一个变量向另外一个变量复制基本类型的值时,会将前者的值克隆一个,而后将克隆的值赋值到后者,所以这两个值是彻底独立的,只是他们的value相同而已。
设计
var num1 = 10; var num2 = num1; console.log(num2);//10
上面的num1中被保存的值为10,当把num1的值赋值给num2时,num2的值也为10。可是这两个10是彻底独立的,num2中的10只是被克隆出来的,至关于我写了一个word文档,把它放到了num1的文件夹中,而后我再复制这个word文档,就叫word副本吧,而后把这个副本放到num2的文件夹下,这两个word文档是彻底同样的,修改任何一个都不会影响两一个。指针
num2 += 1; console.log(num1); //10 console.log(num2); //11
从上面能够看出修改num2的值,num1的值未发生变化。再来看下引用类型的复制。当从一个变量向另外一个变量复制引用类型的值时,一样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。code
var obj1 = { name : "111" }; var obj2 = obj1; console.log(obj2.name); //111
obj2.name = "222";
console.log(obj1.name); //222
第一次打印出的结果为“111”,这个咱们很容易理解,可是第二次打印出来的是“222”,有点莫名其妙了。这就是引用类型和基本类型的不一样之处了。复制对象时并不会在堆内存中新生成一个如出一辙的对象,只是多了一个保存指向这个对象指针的变量罢了。将obj1的值复制给obj2,而这个值的副本其实是一个指针,这个指针指向存储在堆中的一个对象,也就是说建立了一个新的内存地址传给了obj2,obj1和obj2两个变量同时指向了同一个Object,当去改变这个对象时,他们的值都会改变,也就是说他们中任何一个做出的改变都会反映在另外一个身上。下面的简易图可能更明了些。对象
函数参数的传递 blog
《js高级程序设计》上是这样叙述参数传递的:全部函数的参数都是按值传递的,也就是说把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另外一个变量同样。因此若是能理解变量的复制,那么参数的传递也就很简单了。仍是先从基本类型举例说明吧。ip
var count = 10; function num(num1){ num1 = 1;
return num1; } var result = num(count); console.log(result);//1
console.log(count);//10,并未变成1
这个例子很容易理解,实际就是建立了一个count的副本,而后把count的值传入参数中,由于函数中定义了参数的值,因此1就将10覆盖了,最后的result返回1,而count并未发生变化。看一个有关传递对象的例子。
var person = { name : "Tom" }; function obj(peo){ peo.name = "Jerry";
return peo; } var result = obj(person);
console.log(result.name);// Jerry console.log(person.name);// Jerry
在上面的例子中,把person复制传入obj()中,peo和person指向了同一个对象,而在peo中修改了name属性,其实修改了它们共同指向的对象的name属性,相对应的外部person所引用的name属性也就改变了,因此打印出来的为Jerry。其实这个乍一看,感受引用类型的参数是按照引用传递的,这就是我最初犯得错误。再来看一个例子。
var person = { name : "Tom" }; function obj(peo){ peo = { name : "Jerry" }; return peo; } var result = obj(person);
console.log(result.name);// Jerry
console.log(person.name);// Tom
上面的例子中,在函数中从新定义了一个对象,也就是如今堆内存中有两个对象,外部的person指向的是老的对象,被传入参数后指向的是新定义的对象,因此调用后返回的值是新定义的对象的值。若是是参数是按引用传递的,那么person.name打印出来的结果为Jerry,从这点能够得出参数是按值传递的(有的地方叫作按共享传递)。
咱们拿老罗推荐的《人类简史》把它形象化,描述的不太好。简史的第一章标题是“认知革命”,咱们把它名字改成“person”根据后面的页码数能够直接找到“认知革命”的内容“也就是peoson所指向的对象”,第二章是“农业革命”,咱们把它为“result”,其分目录有一节“记忆过载”(更名为“peo”),一样能够直接根据页码找到这一节内容。如今咱们把“person”复制到“peo”中,第二章中的“peo”这一节就变成了“person”,而咱们根据第一章中的“peoson”找到的仍是第一章的内容,这是由于它们指向了不一样的内容板块,互不干扰。在这里,堆内存就是每章的内容,而第一章和第二章内容是2个不一样的对象,而这二者互不相干,所以打印外部person.name时,结果还是之前的对象的属性值。
结论
总而言之,在js中参数都是按值传递的。我写例子粗糙了些,《javascript高级程序设计》中的例子描述的更清晰一些,更易理解。