Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript Arrays Multidimensional Arrays Create a Multidimensional Array

karan Badhwar
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
karan Badhwar
Web Development Techdegree Graduate 18,135 Points

MDN example

There is one example in MDN

let a = [[1], [2], [3]]; let b = [...a];

b.shift().shift(); // 1

// Oh no! Now array 'a' is affected as well: a // [[], [2], [3]]

why the a array gets effected as well as we know spread operator just copies the data and spread it out?

3 Answers

Steven Parker
Steven Parker
229,732 Points

The spread operator only makes a "shallow copy". Since the array contains other arrays, the elements in the copy still refer to the same nested arrays.

So if you did b.shift() it would affect only b and not a, but b.shift().shift() alters the first element that both arrays initially share a reference to.

One way to make a "deep copy" (also known as a "clone") where none of the content is shared is by using the JSON operations:

let b = JSON.parse(JSON.stringify(a));
karan Badhwar
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
karan Badhwar
Web Development Techdegree Graduate 18,135 Points

So basically you are saying Array B holds [array(1), array(1), array(1)] right?

but even if we make a copy of the array A's element how is it making a reference to the elements?

ex- let a = [a]; let b = [a] // array(1); so this means the reference to actual Array A?

Steven Parker
Steven Parker
229,732 Points

In your original example, you are not making a copy of the elements but creating a new array that shares the same elements. This is a difference between a primitive type (like a number) and a reference type (like an array). You can use a comparison to see this, as reference types are only equal if they refer to the same thing(s):

const a = [1, 2, 3];
const b = a;          // b SHARES elements with a
const c = [1, 2, 3];  // c has same VALUES as a
if (a == b) console.log("a and b are equal");
if (a == c) console.log("this will not happen");
else console.log("a and c may have the same values but are NOT equal");

You can also use the example I gave to get a completely separate copy of the entire array and contents. It will also fail a comparison test with "a".

In your newer example (let a = [a]; let b = [a]), the new "a" would now have an array of an array of arrays, and "b" would have an array that refers to the new "a". The deep nesting might be hard to keep track of!

Steven Parker
Steven Parker
229,732 Points

To answer the new questions:

If you assign a primitive (like a number or string), you are passing a copy of the value. And i you assign a reference type (like an array), you are creating a new reference to the same thing.

So, about what b.shift().shift(); does:
Originally a and b shared the same first element, which was [1]. Then b.shift() takes that first element out of b. But chaining on another .shift() takes away the first element of that (leaving an empty array), which can now only be seen as the first element of a.

Your latest example confuses things a bit. You said let c = [a], but the comment was incorrect. if a was [[1], [2], [3]], then c would now be [[[1], [2], [3]]] (more deeply nested). But anytime you chain shifts remember that the first one removes an element from the thing you are working with, and then second one modifies the element that was removed. So the end result of the second one can only be seen using another identifier that still references that original first element. If there were no other identifiers (no "copy"s), there would be no evidence that the second shift did anything at all.

karan Badhwar
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
karan Badhwar
Web Development Techdegree Graduate 18,135 Points

But then, how do we know when we are passing a copy of the value or a reference to the Original value.

And sir I did not understand that how is this ( b.shift().shift(); // 1 ) referring to the actual value

Example - let c = [a] // c = [[1], [2], [3]];

so if i do c.shift() // c = [[2], [3]]

but if i do c.shift().shift() // c = [[2], [3]] & a = [[2], [3]]

and I am sorry to bother this much, actually I am but weak at logical understanding

Steven Parker
Steven Parker
229,732 Points

It gets a bit confusing when you post new questions as an "answer". But I added another comment to my answer.

karan Badhwar
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
karan Badhwar
Web Development Techdegree Graduate 18,135 Points

Thankyou sir, I got it, So this is all because of the Shallow Copies made by the ... spread operator right. Sir thankyou so much bearing my logical issues. I really appreciate it