Search code examples
javascriptarraysecmascript-6spread-syntax

Why is a spread element unsuitable for copying multidimensional arrays?


From mdn: Spread Syntax

Note: Typically the spread operators in ES2015 goes one level deep while copying an array. Therefore, they are unsuitable for copying multidimensional arrays. It's the same case with Object.assign() and Object spread syntax. Look at the example below for a better understanding.

var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// Now array b is: [[2], [3]]

What is the point of the above statement? The above code sample works just the same as if you'd copied the array in a to b using the .slice() method. I tried adding another dimension to the array here: https://repl.it/HKOq/2 and things still worked as expected.

So why is the spread syntax unsuitable for copying multidimensional arrays?

I'd appreciate any help.

EDIT:

Reading the answers by estus and vol7ron helped me figure things out. Basically, as estus points out technically there are just arrays inside arrays rather than multidimensional arrays.

And as vol7ron explains only the first level of the array is copied so the objects in memory remain the same for any further nested elements.

I was also wrong to suspect that using the spread syntax was supposed to behave any differently than the slice operator


Solution

  • Arrays are objects, and [...a] creates a shallow copy of a array object.

    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. This is what

    It's the same case with Object.assign() and Object spread operators

    part refers to.

    And regarding

    The above code sample works just the same as if you'd copied the array in a to b using the .slice() method

    ...it truly does. This is a neater way to write a.slice() or [].concat(a). With a considerable exception. ES6 rest operator (as well as Array.from(a)) works equally for all iterables, not just for arrays.

    For a deep copy of an object ES6 offers nothing new, an object (which an array is) should be recursively copied by hand. To address all the concerns it still makes sense to use proven third-party helper functions, such as Lodash cloneDeep.