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 trialkaran Badhwar
Web Development Techdegree Graduate 18,135 PointsMDN 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
231,269 PointsThe 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
Web Development Techdegree Graduate 18,135 PointsBut 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
231,269 PointsIt gets a bit confusing when you post new questions as an "answer". But I added another comment to my answer.
karan Badhwar
Web Development Techdegree Graduate 18,135 PointsThankyou 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
karan Badhwar
Web Development Techdegree Graduate 18,135 Pointskaran Badhwar
Web Development Techdegree Graduate 18,135 PointsSo 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
231,269 PointsSteven Parker
231,269 PointsIn 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):
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
231,269 PointsSteven Parker
231,269 PointsTo 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]
. Thenb.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.