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
source to share
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
.
source to share
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
source to share
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'
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
source to share
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);
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.
source to share