javascript JS 对象按值复制与按引用复制
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19448646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JS object copy by value vs copy by reference
提问by RuntimeException
I was playing with chrome console and noticed something which I couldn't understand. I know in JS variables are copied by value and objects are copied by reference. Below code works fine as expected which outputs 2 and proves JS objects work as reference:
我在玩 chrome 控制台时注意到了一些我无法理解的东西。我知道在 JS 中变量是按值复制的,而对象是按引用复制的。下面的代码按预期工作正常,输出 2 并证明 JS 对象可以作为参考:
var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2
However this code doesn't work as it should. I expected objB.a to output 2
but it gives 1
instead. Why?
但是,此代码无法正常工作。我希望 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 ??
回答by Joseph
I'd rather think of variables with objects as pointers to objects(like C pointers) rather than references.
我宁愿将带有对象的变量视为指向对象的指针(如 C 指针)而不是引用。
In your third line, you just replaced objA
, making it "point to" another object. It does not changewhatever objB
is "pointing".
在第三行中,您刚刚替换了objA
,使其“指向”另一个对象。它不会改变任何objB
“指向”。
By line 3, objA
now points to {a:2}
while objB
still points to whatever objA
was pointing at the time you assigned it to objB
, at line 2, which is {a:1}
.
通过第 3 行,objA
now 指向{a:2}
whileobjB
仍然objA
指向您objB
在第 2 行将其分配给 时指向的任何内容,即{a:1}
。
line 1: objA -> {a:1}
line 2: objA -> {a:1} <- objB
line 3: objA -> {a:2}, objB -> {a:1}
回答by Aadit M Shah
I like to think of JavaScript variables as sticky notes. A sticky note is a small note which you put on your fridge. What can you write on your sticky note? You can write small pieces of information.
我喜欢将 JavaScript 变量视为便利贴。便利贴是您贴在冰箱上的小纸条。你能在便签上写什么?你可以写一些小信息。
Now there are two types of information in JavaScript - primitive values and reference values. Primitive values are small pieces of information that you can write on your sticky note directly. They include:
现在 JavaScript 中有两种类型的信息 - 原始值和引用值。原始值是您可以直接写在便签上的小块信息。他们包括:
- Booleans
- Numbers
- Strings
- Null
- Undefined
- 布尔值
- 数字
- 字符串
- 空值
- 不明确的
On the other hand reference values are large amounts of information which you can't write on a small sticky note. So how do you store reference values in sticky notes?
另一方面,参考值是大量的信息,你不能写在一张小便签上。那么如何在便利贴中存储参考值呢?
You don't.
你没有。
Reference values (like arrays, objects and functions) are written on a bigger piece of paper and only a reference to them is written on the sticky note. For example, my wife might write:
引用值(如数组、对象和函数)写在一张更大的纸上,只有对它们的引用写在便签上。例如,我的妻子可能会写:
Honey, the list of groceries is under your keyboard.
亲爱的,杂货清单在你的键盘下面。
Here the list of groceries is an array (i.e. a large amount of information). Since we can't write it on a small sticky note we simply write it on a bigger piece of paper and make a sticky note which tells us where it is to be found. In programming terms:
这里的杂货清单是一个数组(即大量信息)。因为我们不能把它写在一张小便签上,我们只需把它写在一张更大的纸上,然后做一张便签,告诉我们在哪里可以找到它。在编程方面:
var groceryList = ["1 apple", "2 bananas", "3 loaves of bread"];
Here the actual grocery list is stored somewhere in memory and only the address of the grocery list is stored in the variable groceryList
.
这里实际的杂货清单存储在内存中的某处,只有杂货清单的地址存储在变量中groceryList
。
So what happens when we assign one variable to another? Let's first take an example of a primitive value:
那么当我们将一个变量分配给另一个变量时会发生什么?我们先举一个原始值的例子:
var x = 2;
var y = x;
alert(y); // 2
y = 3;
alert(x); // 2
This is what's happening:
这是正在发生的事情:
- We write the number
2
on a new sticky note and put it on our fridge. - We copy the number
2
from the sticky notex
onto another sticky notey
and put it on our fridge. - We erase the value of sticky note
y
and write the number3
on it instead. - Now the value of sticky note
x
is2
and sticky notey
is3
.
- 我们
2
在一张新的便利贴上写下这个数字,然后把它放在我们的冰箱上。 - 我们拷贝数量
2
从便签x
到另一个便签y
,并把它放在我们的冰箱。 - 我们擦除便签的值
y
并3
在其上写下数字。 - 现在便签的价值
x
是2
,便签y
是3
。
This is called copy by value because we're just copying the value of sticky note x
onto sticky note y
.
这称为按值复制,因为我们只是将便签的值复制x
到便签上y
。
Now let's take an example of copy by reference. In fact let's take your example of copy by reference:
现在让我们举一个引用复制的例子。事实上,让我们以引用复制为例:
var objA = {a: 1};
var objB = objA;
objA.a = 2;
objB.a; // 2
Here's what's happening in your example:
这是您的示例中发生的事情:
- We create an object
{a: 1}
somewhere in memory and write the address of this object on sticky noteobjA
. Let's call this addressx
for simplicity's sake. - We copy the address
x
from sticky noteobjA
onto another sticky noteobjB
. Now bothobjA
andobjB
reference the same object{a: 1}
stored at memory locationx
. - Hence when we change the value of
objA.a
the same change is reflected onobjB.a
becauseobjA
andobjB
both reference the same object stored at memory locationx
.
- 我们
{a: 1}
在内存中的某处创建一个对象,并在便签上写下这个对象的地址objA
。x
为简单起见,我们称这个地址为。 - 我们将地址
x
从便签objA
复制到另一个便签上objB
。现在,这两个objA
和objB
引用相同的对象{a: 1}
存储在存储器位置x
。 - 因此,当我们改变的值
objA.a
相同的变化的反射objB.a
,因为objA
与objB
两个参考存储在存储单元中的同一个对象x
。
This is called copy by reference because we are simply copying the reference of an object from sticky note objA
to sticky note objB
. We're not copying the actual object.
这称为按引用复制,因为我们只是将对象的引用从便签复制objA
到便签objB
。我们不是在复制实际的对象。
So what's the difference between copy by reference and copy by value? Absolutely nothing. In both cases we're simply copying the value of one sticky note onto another.
那么按引用复制和按值复制有什么区别呢?绝对没有。在这两种情况下,我们只是将一个便签的值复制到另一个上。
Two sticky notes are said to be equivalent only when they contain the exact same information. For example the following are equivalent:
只有当它们包含完全相同的信息时,两个便签才被认为是等效的。例如,以下是等效的:
var x = 2;
var y = 2;
alert(x === y); // true
var o = {a: 1};
var p = o;
alert(o === p); // true
However the following values are not equivalent:
但是,以下值并不等效:
var o = {a: 1};
var p = {a: 1};
alert(o === p); // false
The reason that they are not equivalent is because o
points to an object stored at a memory location say x
while p
points to an object stored at a different memory location say y
. Although both these objects have the exact same properties they are in fact two different objects.
它们不等价的原因是因为o
指向存储在内存位置的对象,比如 ,x
而p
指向存储在不同内存位置的对象,比如y
。尽管这两个对象具有完全相同的属性,但它们实际上是两个不同的对象。
For example no two Nintendo Gameboys are the same no matter how identical they look. In the same spirit let's take a look at your last example:
例如,没有两个 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 ??
Here's what happening in the above code:
这是上面代码中发生的事情:
- We create an object
{a: 1}
at a memory locationx
and write the addressx
on a sticky noteobjA
. - We copy the address
x
from sticky noteobjA
to sticky noteobjB
. Both of them now point to the same object stored at memory locationx
. - We create a new object
{a: 2}
at a memory locationy
and write the addressy
on the stick noteobjA
. NowobjA
has a reference valuey
andobjB
has a reference valuex
. They reference two different objects.
- 我们
{a: 1}
在内存位置创建一个对象x
并将地址写在x
便签上objA
。 - 我们将地址
x
从便签复制objA
到便签objB
。它们现在都指向存储在内存位置的同一个对象x
。 - 我们
{a: 2}
在内存位置创建一个新对象y
并将地址写在y
便签上objA
。现在objA
有了参考价值y
,objB
有了参考价值x
。它们引用两个不同的对象。
As you can see assigning a new reference value to objA
simply overwrites the old reference value. It does not replace the object {a: 1}
with the object {a: 2}
. That's not possible in JavaScript.
正如您所看到的,分配新的参考值objA
只是覆盖旧的参考值。它不会用对象替换{a: 1}
对象{a: 2}
。这在 JavaScript 中是不可能的。
回答by closure
Your first example works as object pointed by both variables are the same.
你的第一个例子是因为两个变量指向的对象是相同的。
In your second example doesn't because you are assigning another objectto objA
at line #3
.
在您的第二个示例中,不是因为您将另一个对象分配给objA
at line #3
。
objA = {a: 2}; //Assigned whole object here instead property.
This will make objA
point to a another object ({a:2}
) while the objB
will be pointing to the old object.
这将objA
指向另一个对象 ( {a:2}
) 而objB
将指向旧对象。
回答by webduvet
ObjB in your case is not pointing to variable objA but to the object where the varable objA is pointing, thus changing the object properties is not the same as changing where the variable points.
在您的情况下,ObjB 不是指向变量 objA,而是指向变量 objA 指向的对象,因此更改对象属性与更改变量指向的位置不同。
In javascript are variables passed by value. It is not any different when it comes to objects. The variable is not pointer to object the same way as in let say C++. It only contains reference to pointer which is accessible only by javascript itself. So when you do:
在 javascript 中是按值传递的变量。当涉及到对象时,这并没有什么不同。变量不是指向对象的指针,就像在 C++ 中一样。它只包含对指针的引用,该指针只能由 javascript 本身访问。所以当你这样做时:
objA = objB
you only copy the reference pointer to object in memory.
您只需将引用指针复制到内存中的对象。
回答by Kos
I was playing with chrome console and noticed something which I couldn't understand. I know in JS variables are copied by value and objects are copied by reference.
我在玩 chrome 控制台时注意到了一些我无法理解的东西。我知道在 JS 中变量是按值复制的,而对象是按引用复制的。
No. Also there's no such thing as "copying by value" or "copying by reference", there's just "copying".
不。也没有“按值复制”或“按引用复制”之类的东西,只有“复制”。
A variable's valueis always refers to some object. The object can be of type Object
, like {}
, or of type Number, like 5
, or any other.
变量的值总是指向某个对象。对象的类型可以是Object
、like{}
或 Number 类型、like5
或任何其他类型。
Assignment and function call never copies objectsin Javascript, it only binds the same value to another variable:
赋值和函数调用永远不会在 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
Copying objects has to be done explicitlyby you, objects don't get copied magically.
复制对象必须由您明确完成,对象不会被神奇地复制。
Copying Object
s makes sense, because an Object
can be modified. However, copying numbers or strings doesn't make sense - you only care that a variable's value refers to 1234
, but you'd never care "which particular 1234". (They have no "identity".)
复制Object
s 是有道理的,因为 anObject
可以修改。但是,复制数字或字符串没有意义——您只关心变量的值指的是1234
,但您永远不会关心“哪个特定的 1234”。(他们没有“身份”。)