众所周知,JavaScript中参数是按值传递的。与访问变量不同,基本类型和引用类型的参数在传递时都如同变量的复制。
但是我们在使用引用类型的参数传递时,经常会发现在函数内改变引用类型参数(如对象)会在函数外反映出来,这种情况貌似与“按值传参”的思想不符?
我本人在这个坑上也摔过很多次,最近遇到了一个新词:call by sharing(按共享传参)让我对这个问题有了比较深刻的认识。分享给对这个问题有误解的童鞋们。。。
先大概介绍按值传参
基本类型
基本类型的参数传递比较简单,示例代码
function add(num){
num+=10;
console.log(num);
}
var str=10;
add(str);//20
console.log(str);//10
str的值复制给了函数add内部的局部变量num,所以在函数内部改变num的值并不会影响外部str的值。
引用类型
红宝书上有这么一句话:在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反应函数外。
用两段代码来说明:
function setName1(obj){
obj.name="Mike";
return obj;
}
var person=new Object();
setName1(person);
console.log(person.name);//'Mike'
这段代码表面上看:函数内部的改变影响了函数外,难道是按引用传递?再看下面这段代码:
function setName2(obj){
obj.name="Mike";
obj={name:"Tom"};
return obj;
}
var person=new Object();
setName2(person);
console.log(person.name);//'Mike'
这个情况就比较有趣了,如果是按引用传递的,函数内函数外始终访问用一个引用,最后的结果应该是“Tom”才对。
再回到之前提到的:在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反应函数外。
其实这句话从另一个角度讲,就是call by sharing(共享传参)的定义。
先看一下ECMAScript中对call by sharing的定义
The main point of this strategy is that function receives the copy of the reference to object. This reference copy is associated with the formal parameter and is its value.
Regardless the fact that the concept of the reference in this case appears, this strategy should not be treated as call by reference (though, in this case the majority makes a mistake), because the value of the argument is not the direct alias, but the copy of the address.
The main difference consists that assignment of a new value to argument inside the function does not affect object outside (as it would be in case of call by reference). However, because formal parameter, having an address copy, gets access to the same object that is outside (i.e. the object from the outside completely was not copied as would be in case of call by value), changes of properties of local argument object — are reflected in the external object.
其实这段话,特别是标粗的地方说明的就是:引用类型把在内存中的地址复制给了函数中的局部变量。
所以出现会两种情况:
改变引用类型的属性
当在函数中改变引用类型(如对象)的属性时,是在同一个内存地址区域进行操作,所以会在函数外反映出来。如setName1列表项目
在函数内,对形参进行了重新复制,即改变了形参的引用,(内存中的地址已经改变),与实参引用已经完全不一样了,所以不会对函数外引用类型变量参数产生影响,如setName2.
个人愚见,欢迎交流讨论。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。