简体   繁体   中英

JS object copy by value vs copy by reference

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:

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?

var objA = {a: 1};
var objB = objA;
objA = {a: 2};  //Assigned whole object here instead property.
objB.a; //1 - Shouldn't this be 2 ??

I'd rather think of variables with objects as pointers to objects (like C pointers) rather than references.

In your third line, you just replaced objA , making it "point to" another object. It does not change whatever objB is "pointing".

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} .

line 1: objA -> {a:1}
line 2: objA -> {a:1} <- objB
line 3: objA -> {a:2}, objB -> {a:1}

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.

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:

  1. Booleans
  2. Numbers
  3. Strings
  4. Null
  5. 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 (ie 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 .


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:

  1. We write the number 2 on a new sticky note and put it on our fridge.
  2. We copy the number 2 from the sticky note x onto another sticky note y and put it on our fridge.
  3. We erase the value of sticky note y and write the number 3 on it instead.
  4. Now the value of sticky note x is 2 and sticky note y is 3 .

This is called copy by value because we're just copying the value of sticky note x onto sticky note 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:

  1. We create an object {a: 1} somewhere in memory and write the address of this object on sticky note objA . Let's call this address x for simplicity's sake.
  2. We copy the address x from sticky note objA onto another sticky note objB . Now both objA and objB reference the same object {a: 1} stored at memory location x .
  3. Hence when we change the value of objA.a the same change is reflected on objB.a because objA and objB both reference the same object stored at memory location 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.

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.

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:

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:

  1. We create an object {a: 1} at a memory location x and write the address x on a sticky note objA .
  2. We copy the address x from sticky note objA to sticky note objB . Both of them now point to the same object stored at memory location x .
  3. We create a new object {a: 2} at a memory location y and write the address y on the stick note objA . Now objA has a reference value y and objB has a reference value x . They reference two different objects.

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.

Your first example works as object pointed by both variables are the same .

In your second example doesn't because you are assigning another object to 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.

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.

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:

objA = objB

you only copy the reference pointer to object in memory.

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.

No. Also there's no such thing as "copying by value" or "copying by reference", there's just "copying".

A variable's value is always refers to some object. The object can be of type Object , like {} , or of type Number, like 5 , or any other.

Assignment and function call never copies objects in Javascript, it only binds the same value to another variable:

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 explicitly by 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".)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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