user2998225
user2998225

Reputation: 53

Why does "a.push(b)" change "b" in my example code?

I'm trying to push a value to an array, but this adds the value to both arrays a and b. How can I make sure that the b array is not modified?

var a=[[1]];
var b= [2];
document.getElementById("1").innerHTML="a[1] "+a[1];
document.getElementById("2").innerHTML="b "+b;

a.push(b);
document.getElementById("3").innerHTML="a[1] "+a[1];
document.getElementById("4").innerHTML="b "+b;

a[1].push([3]);
document.getElementById("5").innerHTML="a[1] "+a[1];
document.getElementById("6").innerHTML="b "+b+" < why did this value changed?";
<div id="1"></div>
<div id="2"></div><br />
<div id="3"></div>
<div id="4"></div><br />
<div id="5"></div>
<div id="6"></div><br />

Upvotes: 5

Views: 359

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074158

When you do a.push(b), a[1] gets a copy of the value in b, which is a reference to the array, not a copy of the array. So you get this:

               +−−−−−−−−−−−−+
a[Ref5845]−−−−>|  (array)   |
               +−−−−−−−−−−−−+     +−−−−−−−−−+
               | 0: Ref9635 |−−−−>| (array) |
               | 1: Ref2235 |−−+  +−−−−−−−−−+
               +−−−−−−−−−−−−+  |  | 0: 1    |
                               |  +−−−−−−−−−+
                               |
                               |  +−−−−−−−−−+
                               +−>| (array) |
                               |  +−−−−−−−−−+
                               |  | 0: 2    |
                               |  +−−−−−−−−−+
b[Ref2235]−−−−−−−−−−−−−−−−−−−−−+

(Those "RefNNNN" values represent reference (kind of like the address of the array in memory, though not literally). We never directly see those references.)

So naturally, it doesn't matter whether you use a[1] or b to get to it, if you modify the state of the array they both point to, you see that modified state regardless of which one you look through.

There are lots of ways to copy an array if that's what you want to do:

a.push(b.slice());          // Just about all versions of JavaScript
// or
a.push(Array.from(b));      // Added in ES2015, easily polyfilled
// or
a.push([...b]);             // Added in ES2015, not easily polyfilled

Note that this is a shallow copy. If the array contains object/array references, then just as with a.push(b), the reference, not the object/array, is copied. More on that in this question's answers.

Upvotes: 2

Fullstack Guy
Fullstack Guy

Reputation: 16908

Just copy the original array using slice() instead of passing the reference. Array.slice() would return a new array instance copied from the original array.

When you are doing a.push(b); you have inserted the reference of the array b into a.

Now when you do a[1].push([3]); you actually insert the array [3] into the b reference which is at index 1 of array a. That is why you are seeing a changed value.

var a=[[1]];
var b= [2];
document.getElementById("1").innerHTML="a[1] "+a[1];
document.getElementById("2").innerHTML="b "+b;

a.push(b.slice());
document.getElementById("3").innerHTML="a[1] "+a[1];
document.getElementById("4").innerHTML="b "+b;

a[1].push([3]);
document.getElementById("5").innerHTML="a[1] "+a[1];
document.getElementById("6").innerHTML="b "+b+" < why did this value changed?";
<div id="1"></div>
<div id="2"></div><br />
<div id="3"></div>
<div id="4"></div><br />
<div id="5"></div>
<div id="6"></div><br />

Note:

For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.

For strings, numbers and booleans (not String, Number and Boolean objects), slice copies the values into the new array. Changes to the string, number or boolean in one array do not affect the other array.

Upvotes: 6

Related Questions