0

Here's an example from the browser console

a=[[1,2,3],[3,2,1]]
b=[]
b.push(a)
a[0][0]=9
b.push(a)

In that case, I was expecting b to be

[[[1,2,3],[3,2,1]],[[9,2,3],[3,2,1]]]

But it will be

[[[9,2,3],[3,2,1]],[[9,2,3],[3,2,1]]]

I'm attaching a screenshot to better show the results in the browser: browsers console with the same code as above and output

Any ideas on why this is happening and how to get to my expecting results?

guitwo
  • 3
  • 3
  • 4
    You are pushing the same reference to the array twice. – Spectric Mar 03 '22 at 04:08
  • Hi @Spectric but it should push the values inside of the variable, not the reference to the value, no? the first time I push `b.push(a)` I expect the values of `a` to be pushed and stay there. But when I change `a` and push it again, both entries will have `a`'s new value – guitwo Mar 03 '22 at 04:13
  • In JavaScript, objects are passed-by-reference; arrays are special objects (run `typeof []`), so arrays are passed-by-reference as well. – code Mar 03 '22 at 04:20

3 Answers3

0

In JavaScript, objects are passed by reference, meaning "copies" of it aren't copies. They point to the same address in RAM, so mutating one reference mutates 'em all.

To apply to this case, if you didn't already know, arrays are special types of objects. To prove this you can run typeof [] in your browser console. That means that arrays inherit the "pass-by-reference" behavior, meaning if you do let c = a then run c[0] = 1, a will be changed as well and vice versa.

To solve this issue you can use Array.prototype.slice:

const a = [[1, 2, 3], [3, 2, 1]];
const b = [];

Array.prototype.pushWithoutReference = function(add) {
  for(let i = 0; i < add.length; i++) {
    this[this.length] = add[i].slice(0);
  }
}

b.pushWithoutReference(a);
a[0][0] = 9;
b.pushWithoutReference(a);
code
  • 5,690
  • 4
  • 17
  • 39
  • Thanks for the explanation, @code I wasn't aware objects were passed by reference on JS, it makes perfect sense now! I tested your solution but it presented the same results, so I came up with this: b.push([]); for(line of a){ b[b.length-1].push(a.slice(0)); } (based on your response and also https://stackoverflow.com/questions/9190518/how-do-i-pass-the-value-instead-of-the-reference-of-an-array) – guitwo Mar 03 '22 at 04:43
  • @guitwo yeah, I forgot that the array was multidimensional. Fixed it in the last edit. – code Mar 03 '22 at 05:16
0

For the language itself, there are no multidimentional arrays - there are another arrays inside an array. It doesn't matter if contains arrays, plain objects, functions, or primitives. For primitives, their values will be copied. Otherwise, the references to objects will be copied.

You can do it via pushing the copies of inner arrays of array a with the help of map and spread operator(...).

var a=[[1,2,3],[3,2,1]];
var b=[];
b.push(a.map(x=>[...x]));
a[0][0]=9;
b.push(a);
console.log(b);
Abhijeet Vadera
  • 491
  • 2
  • 7
0

Ok, based on all the comments here, specially @code 's one, and also another post (How do I pass the value instead of the reference of an array?) I was able to achieve the results by using this:

b.push([]); 
for(line of a){ 
    b[b.length-1].push(a.slice(0)); 
}

EDIT

Abhijeet's suggestion also works flawlessly:

b.push(a.map(x=>[...x]));
guitwo
  • 3
  • 3