我现在正在节点中进行一些编程,我对函数范围的处理感到惊讶。我被引导相信现在ES6的范围更加严格。以下按预期工作:
function f(v){
v += 1;
return v;
}
let before = 1;
let after = f(before);
console.log(after); // This logs 2 (as expected)
console.log(before); // This logs 1 (as expected)
但是当我使用对象/字典做同样的事情时,变量的范围似乎超出了函数:
function f(v){
v.a += 1;
return v;
}
let before = {a: 1};
let after = f(before);
console.log(after.a); // This logs 2 (as expected)
console.log(before.a); // This also logs 2 (I was expecting this to still be 1)
为什么这样的情况呢?为什么v
的范围仅限于函数int
,而不是当它是一个对象时?
答案 0 :(得分:1)
此处的范围没有任何问题。 您的代码只是将对象分配给另一个变量,因此每当您编辑对象时,所有分配的变量都会受到影响:
let o1 = {
a: 1
};
let o2 = o1;
o1.a++;
console.log(o2);
答案 1 :(得分:1)
Javascript有两种数据类型:primitive和Object。
在您的第一个示例中,您传入原语数据类型(布尔值,空值,未定义,字符串,符号和数字 - 您的情况)。当您将这些类型的变量传递给函数时,您将传递一个副本 - 因此修改的任何内容都不会影响初始值/变量,就像在第一种情况下一样。
使用 Object 数据类型,当您将对象传递给函数时,您将传入对该对象的值的引用 - 而不是该值的副本,和原始一样。因此,当您在函数中修改它时,您将修改引用。这意味着具有此引用的任何变量也将具有修改后的值,因为它们只是指向最近修改过的值。
答案 2 :(得分:1)
JavaScript函数pass all arguments 按值。
在第一种情况下,您有一个原始值(数字是原始的)。因此,before
指的是一个原语,值1.您将其传入 - 它按值传递 。你返回一个值。将其分配给第二个对象。 after
是另一个对象。基本上,两个指针,到不同的对象。不同的对象。不同的价值观。
从垃圾收集的角度来考虑它。你失去了#34;之前"超出你的范围。无法再访问1
原语。免费清理。
在第二种情况下,您传递对象引用的值。然后再次返回对象引用的值。因此before
和after
指的是同一个对象。它们是不同的参考。因此,在console.log(before)
和console.log(after)
中,您引用相同的对象和相同的(现在已修改的)值。
现在,再看看垃圾收集器。删除对before
的访问权限。垃圾收集器删除它的值(基本上是指向对象{v:2}的指针)。它可以删除对象本身吗?不,还没有,因为after
的值仍指向此对象。但无论如何,两个变量都指向同一个对象。