采取以下代码
var a = b = [];
a.push('value');
if (a === b) {
console.log('a === b'); // this will execute
}
console.log(a, b); // ["value"] ["value"]
是什么给出的?为什么a
和b
都被修改了? var
声明b
是a
的实时副本吗?如果是这样,那么为什么不能同样适用于常规变量赋值,例如:
var a = b = '';
a = 'value';
if (a === b) {
console.log('a === b'); // this will never run
}
console.log(a, b); // value
当然,使用以下声明解决了初始示例中的问题:
var a = [], b = [];
但是最初例子中的行为让我感到奇怪,特别是它只适用于数组操作。
如果有帮助,我使用的是Google Chrome 10.0.648.82测试版
答案 0 :(得分:6)
grok需要的概念是引用。当您将一个变量分配给指向ECMAScript中的对象([]
,new Array
,{}
,new Object
,函数等)的另一个变量时,参考是通过。除非您创建新对象并将其分配给b
,否则a
会引用b
。
重申一下,var a = [], b = []
会创建两个不同的数组。 var a = b = []
将b
分配给[]
,然后b
分配给a
,{{1}}选择存储在内存中的相同确切对象。任何mutator方法都会改变该对象,分配给该对象的任何变量都将引用该对象。
答案 1 :(得分:4)
当您在变量中存储“对象”(包括数组)时,您实际存储的是对象的引用(或“指针”),而不是对象的副本对象本身。也就是说,对象存在于内存中,并且存储在变量中的是一条信息,告诉解释器在哪里找到该对象。
相比之下,数字或布尔等基元实际上存储在中变量。
所以在我最好的ASCII艺术中,当你有代码
var y = [];
...你最终得到了这个:
+−−−−−−−−−−+ | y | +−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−+ | Ref55467 |−−−−−−−−−−−>| The actual array | +−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−+ | [] | +−−−−−−−−−−−−−−−−−−+
(显然,Ref55467
只是一个例子,你实际上永远无法在代码中看到对象引用的基础值。)
......而与:
var x = 32;
...你最终得到:
+−−−−−−−−−−+ | x | +−−−−−−−−−−+ | 32 | +−−−−−−−−−−+
现在让我们来看看你的
var a = b = [];
看起来像这样:
+−−−−−−−−−−+ | a | +−−−−−−−−−−+ | Ref55467 |−−−−−−+ +−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−−+ +−−−−>| The actual array | | +−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ | | [] | | b | | +−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−+ | | Ref55467 |−−−−−−+ +−−−−−−−−−−+
a
和b
引用(指向)内存中的相同的数组,因此更改数组的操作会更改数组,无论您使用哪个引用调用它们。
与之相反:
var a = b = 32;
....看起来像:
+−−−−−−−−−−+ | a | +−−−−−−−−−−+ | 32 | +−−−−−−−−−−+ +−−−−−−−−−−+ | b | +−−−−−−−−−−+ | 32 | +−−−−−−−−−−+
数字32实际存储在每个地方,而不是两个变量指向的中心位置。
将值传递给函数时也是如此。使用对象引用时,传递给函数的值是对象引用。您实际上并没有将对象传递给函数,只是对它的引用。这意味着如果函数使用引用来操作对象,则会在调用代码中看到结果。例如:
function foo(theArray) {
theArray[0] = 1;
}
var a = ["one", "two", "three"];
foo(a);
alert(a[0]); // alerts "1"
当我们调用foo
时,我们将引用传递给数组对象,因此当foo
使用它来修改数组时,我们会看到结果。< / p>
答案 2 :(得分:2)
它不是实时副本,它是引用同一实例的对象。
当您运行[]
时,您正在执行new Array()
,因此,您要将新的Array
实例分配给a
和b
。