我正在玩Chrome控制台并注意到一些我无法理解的东西.我知道JS变量是按值复制的,对象是通过引用复制的.下面的代码工作正常,输出2并证明JS对象作为参考:
var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2
Run Code Online (Sandbox Code Playgroud)
但是,此代码无法正常工作.我期望objB.a输出,2但它给出了1.为什么?
var objA = {a: 1};
var objB = objA;
objA = {a: 2}; //Assigned whole object here instead property.
objB.a; //1 - Shouldn't this be 2 ??
Run Code Online (Sandbox Code Playgroud)
Jos*_*eph 12
我宁愿把对象变量看作对象的指针(比如C指针)而不是引用.
在你的第三行,你刚刚更换objA,使其"指向"另一个对象.它不会改变任何objB"指向".
通过3线,objA现在指向{a:2},同时objB仍指向任何objA指着你把它分配给时间objB,在第2行,这是{a:1}.
line 1: objA -> {a:1}
line 2: objA -> {a:1} <- objB
line 3: objA -> {a:2}, objB -> {a:1}
Run Code Online (Sandbox Code Playgroud)
我喜欢将JavaScript变量视为便签.粘滞便笺是放在冰箱上的小纸条.你能用粘滞便笺写什么?您可以编写小块信息.
现在JavaScript中有两种类型的信息 - 原始值和参考值.原始值是您可以直接在便签上写下的一小段信息.他们包括:
另一方面,参考值是大量的信息,你不能在一个小的便利贴上写.那么如何在粘滞便笺中存储参考值?
你没有.
参考值(如数组,对象和函数)写在更大的纸上,只有对它们的引用才会写在便签上.例如,我的妻子可能写道:
亲爱的,杂货清单在你的键盘下面.
这里的杂货清单是一个数组(即大量的信息).因为我们不能用一个小的便条写它,我们只需将它写在一张更大的纸上,并制作一个粘滞便笺,告诉我们它在哪里被发现.在编程方面:
var groceryList = ["1 apple", "2 bananas", "3 loaves of bread"];
Run Code Online (Sandbox Code Playgroud)
这里实际的购物清单存储在存储器中的某处,并且只有购物清单的地址存储在变量中groceryList.
那么当我们将一个变量分配给另一个时会发生什么 让我们首先举一个原始值的例子:
var x = 2;
var y = x;
alert(y); // 2
y = 3;
alert(x); // 2
Run Code Online (Sandbox Code Playgroud)
这就是发生的事情:
2在一个新的便利贴上并放在我们的冰箱上.2粘滞便笺x上的数字复制到另一张便条上y并放在我们的冰箱上.y并3在其上写下数字.x是2和便条y是3.这称为按值复制,因为我们只是将便签的值复制x到便利贴上y.
现在让我们以参考为例进行复制.事实上,让我们以你的参考为例进行复制:
var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2
Run Code Online (Sandbox Code Playgroud)
这是你的例子中发生的事情:
{a: 1}在内存中的某处创建一个对象,并在便利贴上写下该对象的地址objA.x为简单起见,我们称这个地址.x粘滞便笺中的地址复制objA到另一个便笺上objB.现在,这两个objA和objB引用相同的对象{a: 1}存储在存储器位置x.objA.a,相同的变化的值被反映在objB.a因为objA并且objB两者都引用存储在存储器位置的相同对象x.这称为引用复制,因为我们只是将对象的引用从便签复制objA到便签objB.我们不是在复制实际的对象.
那么按引用复制和按值复制有什么区别?绝对没有.在这两种情况下,我们只是将一个便利贴的值复制到另一个便利贴上.
只有当它们包含完全相同的信息时,才会说两个粘滞便笺是等效的.例如,以下内容是等效的:
var x = 2;
var y = 2;
alert(x === y); // true
var o = {a: 1};
var p = o;
alert(o === p); // true
Run Code Online (Sandbox Code Playgroud)
但是,以下值不相等:
var o = {a: 1};
var p = {a: 1};
alert(o === p); // false
Run Code Online (Sandbox Code Playgroud)
究其原因,他们是不等价的,因为o点存储在内存位置中的目标说x的同时p指向存储在不同的存储位置中的目标说y.虽然这两个对象具有完全相同的属性,但它们实际上是两个不同的对象.
例如,无论两个Nintendo Gameboys看起来多么相同,都没有两个相同.以同样的精神让我们来看看你的最后一个例子:
var objA = {a: 1};
var objB = objA;
objA = {a: 2}; //Assigned whole object here instead property.
objB.a; //1 - Shouldn't this be 2 ??
Run Code Online (Sandbox Code Playgroud)
以下是上述代码中发生的情况:
{a: 1}在内存位置创建一个对象,x并x在便利贴上写下该地址objA.x从便利贴复制objA到便利贴objB.它们现在都指向存储在存储器位置的相同对象x.{a: 2}在内存位置创建一个新对象,y并y在贴纸上写下地址objA.现在objA有一个参考值y并objB具有参考值x.他们引用两个不同的对象.如您所见,分配新的参考值objA只是覆盖旧的参考值.它不会用对象替换{a: 1}对象{a: 2}.这在JavaScript中是不可能的.