为什么spread元素不适合复制多维数组?

时间:2017-04-15 02:55:56

标签: javascript arrays ecmascript-6 spread-syntax

来自mdn:Spread Syntax

  

注意:通常,ES2015中的扩展运算符在复制数组时会变深一级。因此,它们不适合复制多维数组。与Object.assign()和Object spread语法的情况相同。请查看下面的示例以便更好地理解。

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

以上陈述的重点是什么?上面的代码示例的工作方式与使用.slice()方法将数组复制到a中的方法相同。我尝试在这里向数组添加另一个维度:https://repl.it/HKOq/2并且事情仍按预期工作。

那么为什么扩展语法不适合复制多维数组呢?

我很感激任何帮助。

编辑:

阅读estus和vol7ron的答案帮助我解决问题。基本上,正如estus在技术上指出的那样,数组内部只有数组而不是多维数组。

正如vol7ron解释的那样,只复制了数组的第一级,因此内存中的对象对于任何其他嵌套元素保持不变。

我怀疑使用扩展语法与切片运算符的行为有什么不同我也错了

4 个答案:

答案 0 :(得分:3)

数组是对象,[...a]创建a数组对象的副本。

对于语言本身,没有多维数组 - 数组中有另一个数组。包含数组,普通对象,函数或基元是无关紧要的。对于基元,将复制它们的值。否则,将复制对象的引用。这就是

  

与Object.assign()和对象扩展运算符

的情况相同

部分指的是。

关于

  

上面的代码示例的工作方式与使用.slice()方法将数组复制到a中的方法相同

......确实如此。这是写a.slice()[].concat(a)的简洁方法。有一个相当大的例外。 ES6 rest运算符(以及Array.from(a))对所有迭代都有效,不仅适用于数组。

对于对象的副本,ES6不提供任何新内容,应该手动递归地复制对象(数组)。为解决所有问题,使用经过验证的第三方帮助函数仍然有意义,例如Lodash cloneDeep

答案 1 :(得分:3)

男人,程序员在展示实际显示差异的例子时表现得很差。

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);

输出:

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

注意一些可疑的东西?两个数组[0][0][0]的值都已更改。这意味着位于[0][0][0]的两个数组中的对象引用到同一个对象,而不是副本。但是[1]值不同意味着它确实是副本

浅拷贝表示第一级是复制,更深层次是引用

答案 2 :(得分:1)

因此,该示例试图传达的是var b = [...a];不会展开 a的内部数组(例如b = [1,2,3]),而是b {1}}将[[1],[2],[3]]。因此,b.shift()会移除并返回b的{​​{1}}的第一个元素,然后第二个[1]只会从返回的数组中删除shift()。用一个词1只能达到你的 spreaded 数组的一个级别,例如...var b =[...a]相同,而不是示例中的var b = [a[0], a[1], a[2]]

答案 3 :(得分:1)

不为内部数组元素创建新数组(对于多维数组):

// 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'

它的工作方式与slice()类似,因此您必须遍历数组并为每个维度创建新数组。这是一个简单的例子:

// 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