对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

所以函数的参数都是按值传递的,唯一不同的是因为引用类型,是一个值类型的变量类型,然后这个变量指向一个对象在堆内存当中的地址。所以我们直接操作这个变量,则同时会更新对象的值。

posted @ 2021-09-17 17:50  jerryfish  阅读(45)  评论(0编辑  收藏  举报