繁体   English   中英

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

[英]JS object copy by value vs copy by reference

我正在玩Chrome控制台并注意到一些我无法理解的东西。 我知道JS变量是按值复制的,对象是通过引用复制的。 下面的代码工作正常,输出2并证明JS对象作为参考:

var objA = {a: 1};
var objB = objA;
objA.a = 2; 
objB.a; // 2

但是,此代码无法正常工作。 我期望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 ??

我宁愿把对象变量看作对象的指针 (比如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}

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

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

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

另一方面,参考值是大量的信息,您无法在小便利贴上书写。 那么如何在粘滞便笺中存储参考值?

你没有。

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

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

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

var groceryList = ["1 apple", "2 bananas", "3 loaves of bread"];

这里实际的购物清单存储在存储器中的某处,并且只有购物清单的地址存储在变量groceryList


那么当我们将一个变量分配给另一个时会发生什么 让我们首先举一个原始值的例子:

var x = 2;
var y = x;
alert(y);  // 2
y = 3;
alert(x);  // 2

这就是发生的事情:

  1. 我们在新的便利贴上写下2号并将其放在我们的冰箱上。
  2. 我们将粘滞便笺x的数字2复制到另一个粘滞便笺y并将其放在我们的冰箱上。
  3. 我们删除便签y的值并在其上写上数字3
  4. 现在粘滞便笺x的值是2 ,粘滞便笺y3

这被称为copy by value,因为我们只是将便签x的值复制到便签y

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

var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2

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

  1. 我们在内存中的某处创建一个对象{a: 1} ,并在便签objA上写下该对象的地址。 为简单起见,我们称这个地址为x
  2. 我们将粘滞便笺objA的地址x复制到另一个粘滞便笺objB 现在objAobjB引用存储在存储位置x的相同对象{a: 1}
  3. 因此,当我们更改objA.a的值时,相同的更改会反映在objB.a因为objAobjB都引用存储在内存位置x的相同对象。

这被称为引用副本,因为我们只是将对象的引用从便签objA到便签objB 我们不是在复制实际的对象。

那么按引用复制和按值复制有什么区别? 绝对没有。 在这两种情况下,我们只是将一个便利贴的值复制到另一个便利贴上。

只有当它们包含完全相同的信息时,才会说两个粘滞便笺是等效的。 例如,以下内容是等效的:

var x = 2;
var y = 2;
alert(x === y); // true

var o = {a: 1};
var p = o;
alert(o === p); // true

但是,以下值不相等:

var o = {a: 1};
var p = {a: 1};
alert(o === p); // false

它们不相等的原因是因为o指向存储在存储器位置的对象说xp指向存储在不同存储位置的对象,例如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 ??

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

  1. 我们在内存位置x创建一个对象{a: 1} ,并在粘滞便笺objA上写入地址x
  2. 我们将地址x从便签objA到便签objB 它们现在都指向存储在存储位置x的相同对象。
  3. 我们在内存位置y创建一个新对象{a: 2} ,并在贴笔记objA上写入地址y 现在objA具有参考值y并且objB具有参考值x 他们引用两个不同的对象。

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

你的第一个例子就像两个变量所指向的对象一样

在你的第二个例子中没有,因为你在line #3 objA 另一个对象分配给objA

objA = {a: 2};  //Assigned whole object here instead property.

这将使objA指向另一个对象( {a:2} ),而objB将指向旧对象。

在您的情况下,ObjB不是指向变量objA而是指向可变量objA指向的对象,因此更改对象属性与更改变量指向的位置不同。

在javascript中是通过值传递的变量。 对于物体而言,它没有任何不同。 变量不是指向对象的指针,就像在C ++中一样。 它只包含对只能由javascript本身访问的指针的引用。 所以当你这样做时:

objA = objB

您只将引用指针复制到内存中的对象。

我正在玩Chrome控制台并注意到一些我无法理解的东西。 我知道JS变量是按值复制的,对象是通过引用复制的。

不。也没有“按价值复制”或“按参考复制”这样的东西,只是“复制”。

变量的总是指某个对象。 对象可以是Object类型,如{} ,类型为Number,如5 ,或任何其他类型。

赋值和函数调用从不在Javascript中复制对象 ,它只将相同的值绑定到另一个变量:

var a = {},  b = 5;
var a1 = a,  b1 = b;
// variables a and a1 refer to the same object, {}
// variables b and b2 refer to the same object, 5

a['x'] = 10; // the object referred to by a and a1 is modified
a = {'x': 10} // now a refers to a new object and a1 is unaffected

b += 10; // b and b1 now point to a different objects, 15 and 5

function foo(x) {
    ...
}
foo(a); // x inside foo is the same object, {}
foo(b); // x inside foo is the same object, 5

复制对象必须由您明确地完成,对象不会被神奇地复制。

复制Object是有意义的,因为可以修改Object 但是,复制数字或字符串没有意义 - 你只关心变量的值是指1234 ,但你永远不会关心“哪个特定的1234”。 (他们没有“身份”。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM