JS对象按值复制与按引用复制

Run*_*ion 8 javascript

我正在玩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)

  • 您应该使用更简单的类比来解释按值复制与按引用复制.许多初学者发现指针难以理解.对你我来说很容易,但很多人发现StackOverflow的答案很难理解.这个想法是分享你的直觉,而不仅仅是你的知识.让它变得尽可能简单,就像你向一个6岁的孩子解释这个概念一样.不过我必须承认你写了一个很好的答案. (2认同)

Aad*_*hah 5

我喜欢将JavaScript变量视为便签.粘滞便笺是放在冰箱上的小纸条.你能用粘滞便笺写什么?您可以编写小块信息.

现在JavaScript中有两种类型的信息 - 原始值和参考值.原始值是您可以直接在便签上写下的一小段信息.他们包括:

  1. 布尔
  2. 数字
  3. 字符串
  4. 空值
  5. 未定义

另一方面,参考值是大量的信息,你不能在一个小的便利贴上写.那么如何在粘滞便笺中存储参考值?

你没有.

参考值(如数组,对象和函数)写在更大的纸上,只有对它们的引用才会写在便签上.例如,我的妻子可能写道:

亲爱的,杂货清单在你的键盘下面.

这里的杂货清单是一个数组(即大量的信息).因为我们不能用一个小的便条写它,我们只需将它写在一张更大的纸上,并制作一个粘滞便笺,告诉我们它在哪里被发现.在编程方面:

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)

这就是发生的事情:

  1. 我们将这个号码写2在一个新的便利贴上并放在我们的冰箱上.
  2. 我们将2粘滞便笺x上的数字复制到另一张便条上y并放在我们的冰箱上.
  3. 我们删除粘滞便笺的值y3在其上写下数字.
  4. 现在便条的价值x2和便条y3.

这称为按值复制,因为我们只是将便签的值复制x到便利贴上y.

现在让我们以参考为例进行复制.事实上,让我们以你的参考为例进行复制:

var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2
Run Code Online (Sandbox Code Playgroud)

这是你的例子中发生的事情:

  1. 我们{a: 1}在内存中的某处创建一个对象,并在便利贴上写下该对象的地址objA.x为简单起见,我们称这个地址.
  2. 我们将x粘滞便笺中的地址复制objA到另一个便笺上objB.现在,这两个objAobjB引用相同的对象{a: 1}存储在存储器位置x.
  3. 因此,当我们改变时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)

以下是上述代码中发生的情况:

  1. 我们{a: 1}在内存位置创建一个对象,xx在便利贴上写下该地址objA.
  2. 我们将地址x从便利贴复制objA到便利贴objB.它们现在都指向存储在存储器位置的相同对象x.
  3. 我们{a: 2}在内存位置创建一个新对象,yy在贴纸上写下地址objA.现在objA有一个参考值yobjB具有参考值x.他们引用两个不同的对象.

如您所见,分配新的参考值objA只是覆盖旧的参考值.它不会用对象替换{a: 1}对象{a: 2}.这在JavaScript中是不可能的.