对JavaScript按值传递参数的理解
阅读红宝书看到的关于JavaScript参数传递的讲解,ECMAScript中所有函数的参数都是按值传递的。
变量有按值和按引用访问,但是传参只有按值传递。
按值传递参数时,值会被复制到一个局部变量(即一个命名参数,或者用ECMAScript的话说,就是arguments对象中的一个槽位)。
原始数据类型的例子。
function addTen(num){ num += 10; return num; } let count = 20; let result = addTen(count); console.log(count); //20,没有变化 console.log(result);//30
如果是引用数据类型呢?
function setName(obj){ obj.name = "Nicholas"; } let person = new Object(); setName(person); console.log(person.name); //"Nicholas"
这次创建对象保存在person中,在函数内部obj和person都指向了同一个对象。结果就是即使对象按值传进函数,obj也会通过引用访问对象。当函数内部给obj设置了name属性时,函数外部的对象也会反映这个变化,因为obj指向的对象保存在全局作用域的堆内存上。但这并不意味着是按引用传递的。
为了证明对象是按值传递的,在看下面的例子
function setName(obj){ obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } let person = new Object(); setName(person); console.log(person.name); //"Nicholas"
这个例子可以看到当我们将传入的obj指向一个新的对象的时候,在修改name属性就已经不会引起person的属性值。那这个怎么理解呢?
那现在我们用一个图来说明:
这里简单说明一下:
当调用方法setName(person);的时候,函数的参数都是值传递的,这个时候,值传递说的是:js会在栈的存储空中复制一个person变量的副本,二者都指向第一个创建的new object()。两个变量都指向同一个堆地址。
obj.name = "Nicholas"; 更新的是第一个创建的object对象。
obj = new Object(); 创建第二个object对象,同时将obj变量指向到第二个object对象的堆地址。
obj.name = "Greg"; 更新的是第二个object对象。
console.log(person.name); person这个变量一直指向的都是第一个object对象,所以这里输出的还是Nicholas。
所以函数的参数都是按值传递的,唯一不同的是因为引用类型,是一个值类型的变量类型,然后这个变量指向一个对象在堆内存当中的地址。所以我们直接操作这个变量,则同时会更新对象的值。