Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javascript 到底是按值传递还是按引用传递? #3

Open
sunhengzhe opened this issue Jul 21, 2017 · 1 comment
Open

javascript 到底是按值传递还是按引用传递? #3

sunhengzhe opened this issue Jul 21, 2017 · 1 comment

Comments

@sunhengzhe
Copy link
Member

楠哥在第一周文章分享中分享了一个 StackOverflow 上讨论 javascript 是按值传递还是按引用传递的问题:Is JavaScript a pass-by-reference or pass-by-value language?

关于 javascript 中的函数参数传递类型的讨论,大致就是在基本类型和引用类型之间产生了矛盾。

example 1

function addTen(num) {
  num += 10;
}

var count = 20;
addTen(count);
console.log(count); // 20

count 经过 addTen 方法处理后没有变化,所以是按值传递吗?

example 2

function setName(obj) {
  obj.name = 'Nicholas';
}

var obj = {};
setName(obj);
console.log(obj.name); // 'Nicholas'

obj 经过 setName 方法处理后,添加了 name 属性,并赋值为了 Nicholas,所以是按引用传递吗?

我专门翻了一下《Javascript 高级程序设计》,在 4.1 节 基本类型和引用类型的值(p70)里其实已经给出了结论

ECMAScript 中所有函数的参数都是 按值传递 的。
......在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量
......在向参数传递引用类型的值时,会把 这个值在内存中的地址 复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部

所以 example 2 中的 obj 并不是按引用传递,而是 按值传递,只不过这个值就是 obj 在内存中的地址

书中给出的解释如下

基本数据类型显而易见是按值传递,就不解释了。而如何证明对象也是按值传递的呢,看下面这个例子

function setName(obj) {
  obj.name = 'Nicholas';
  obj = {};
  obj.name = 'Greg';
}

var obj = {};
setName(obj);
console.log(obj.name); // 'Nicholas'

如果 javascript 是按引用传递,那么 obj 就会被修改为指向 name 为 'Greg' 的新对象,然而 obj 的 name 仍为 'Nicholas'。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。

回到 StackOverflow 上的问题,高票问答得出的结论是

Instead, the situation is that the item passed in is passed by value. But the item that is passed by value is itself a reference. Technically, this is called call-by-sharing.

回答大概也是这个意思,但是他提到了另外一种说法:call-by-sharing。从 call-by-sharing 的行为来看,确实可以将 javascript 的参数传递描述成 call-by-sharing。

For immutable objects, there is no real difference between call by sharing and call by value, except if object identity is visible in the language. The use of call by sharing with mutable objects is an alternative to input/output parameters:[9] the parameter is not assigned to (the argument is not overwritten and object identity is not changed), but the object (argument) is mutated.

@gp0320
Copy link

gp0320 commented May 2, 2018

function setName(obj) {
obj.name = 'Nicholas';
obj = {};
obj.name = 'Greg';
}

var obj = {};
setName(obj);
console.log(obj.name); // 'Nicholas'
关于上面代码
我来总结一下:按此思路理解
当这个运行的时候呢: setName(obj);
函数 setName 其实是这样 :
在函数内声明局部变量obj,赋值为实参。
function setName(let obj = 传进来的对象引用) {
obj.name = 'Nicholas';
obj = {}; // 局部变量指向另一个对象了
obj.name = 'Greg';
}
是不是一下秒懂?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment