Why is spread element not suitable for copying multidimensional arrays?

From mdn: Distribution Syntax

Note. Typically spread statements in ES2015 go one level deep when copying an array. Therefore they are not suitable for copying multidimensional arrays. This is the same case with the Object.assign () and Object spread operators. Take a 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 meaning of the above? The above code example works the same as if you were to copy the array from a to b using the .slice () method. I tried adding another dimension to the array here: https://repl.it/HKOq/2 and everything still worked as expected.

So why is the spreading operator unsuitable for copying multidimensional arrays?

Any help would be appreciated.

EDIT:

Reading the answers by estus and vol7ron helped me figure it out. Basically, as estum points out, there are technically only arrays within arrays, not multidimensional arrays.

And as vol7ron explains that only the first level of the array is copied, so the objects in memory remain unchanged for any additional nested elements.

I was also wrong in thinking that using the spread operator should behave differently than the slice operator

+3


source to share


4 answers


Arrays are objects, and [...a]

creates a shallow copy of the array object a

.

For the language itself, there are no multidimensional arrays - there are other arrays in the array. It doesn't matter if it contains arrays, simple objects, functions, or primitives. For primitives, their values ​​will be copied. Otherwise, the object references will be copied. This is what

In the same case with the Object.assign () and Object spread operators

points to.



And regarding

The above code example works the same as if you copy the array from a to b using the .slice () method

... it really is. This is an easier way to write a.slice()

or [].concat(a)

. With a significant exception. ES6 break operator (as well as Array.from(a)

) works the same for all iterations, not just arrays.

For a deep copy of an object, ES6 doesn't offer anything new, the object (which is an array) must be manually copied recursively. It still makes sense to use proven third-party helper functions like Lodash to solve all problems cloneDeep

.

+3


source


So an example of trying to show that var b = [...a];

will not expand internal arrays a

(for example b = [1,2,3]

), but instead b

will be [[1],[2],[3]]

. So b.shift()

removes and returns the first element b

that is equal [1]

, then the second one shift()

simply removes 1

from that returned array. In a word ...

, it only reaches one level down into your distributed array for example. var b =[...a]

equivalent var b = [a[0], a[1], a[2]]

, not var b = [ a[0][0], a[1][0], a[2][0] ]

in example



+1


source


New arrays are not created for internal array elements (for multidimensional array):

// One-dimensional array
var a = [1,2,3];
var b = [...a];

a[0]='a';
console.log('a',a);
console.log('b',b);   
  // expected: b[0] == 1
  // got:      b[0] == 1



// Multi-dimensional array
var a = [[1], [2], [3]];
var b = [...a];

a[0][0]='a';
console.log('a',a);
console.log('b',b);   
  // expected: b[0][0] == 1
  // got:      b[0][0] == 'a'
      

Run codeHide result


It works like slice()

, so you'll have to traverse the array and create new arrays for each dimension. Here's one quick example:

// Multi-dimensional array
var a = [[1], [2], [3]];
var b = (function fn(ar){
 return ar.map(el=>Array.isArray(el)&&fn(el)||el) 
})(a);

a[0][0]='a';
console.log('a',a);
console.log('b',b);   
  // expected: b[0][0] == 1
  // got:      b[0][0] == 1
      

Run codeHide result


+1


source


Man, programmers are really bad at displaying examples that actually show the difference.

var a = [[['a', 'b'], ['c', 'd']], 'e'];
var b = [...a];
b[0][0][0] = 'z';
b[1] = 'x';
console.log('a', a);
console.log('b', b);
      

Run codeHide result


Output:

a [[["z", "b"], ["c", "d"]], "e"]
b [[["z", "b"], ["c", "d"]], "x"]

      

Anything suspicious? The array value has [0][0][0]

been changed. This means that an object [0][0][0]

in both arrays refers to the same object and is not a copy. However, the meanings [1]

differ, which means it is indeed a copy.

Shallow copy means that the first level is copied, which are referenced by deeper levels.

+1


source







All Articles