2017-04-15 38 views
2

从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()方法将数组复制到b中相同。我尝试在此处添加另一个维度:https://repl.it/HKOq/2,并且事情仍按预期工作。

那么为什么扩散算子不适合复制多维数组?

我很感激任何帮助。

编辑:

读通过estus和vol7ron答案帮我理出头绪。基本上,正如estus在技术上指出的那样,阵列中只有数组而不是多维数组。

而且,vol7ron只解释了数组的第一层被复制,因此内存中的对象对于任何其他嵌套元素都保持不变。

我也错了,怀疑利用扩展运营商应该比切片运营商不同的行为任何

+0

['''不是操作员!](http://stackoverflow.com/a/37152508/218196) –

+0

@ FelixKling - 请修改MDN文章,该文章多次重复传播错误其余语法。 '...'是用于休息和传播语法的[*标点符号*](http://ecma-international.org/ecma-262/7.0/index.html#sec-punctuators)。 – RobG

回答

3

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

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

这是相同的情况下,与Object.assign()和对象蔓延运营商

部分指。

和关于

,如果你想复制一个数组b使用.slice()方法

上面的代码示例工程一样的...它真正的确实。这是写一个更好的方法a.slice()[].concat(a)。有一个相当大的例外。 ES6休息操作符(以及Array.from(a))对所有迭代操作都是一样的,而不仅仅是阵列操作。

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

+0

所以你用其他语言说你可以有真正的多维数组,它的内存全是1个数组? – MattGoldwater

+0

我诚实地不记得这样的语言,至少将n维数组作为单独的语言实体并不是很实际。如果你有其他高级语言的经验,你可能已经知道规则 - 数组副本通常意味着一个浅拷贝(除非另有证明)。 – estus

+1

顺便说一句,要弄清楚ES6是如何工作的,Babel和Typescript REPLs是不可或缺的。 Babel输出对规格更加严格,TS输出更容易阅读;两者都有帮助。 – estus

0

那么什么的例子是试图传达的是var b = [...a];不会展开a内阵列(例如b = [1,2,3]),但b将是[[1],[2],[3]]。因此,b.shift()删除并返回b的第一个元素,即[1],然后第二个shift()刚从该返回的数组中删除1。在一个单词中,...只能达到一个级别,例如排列在的排列的阵列中。 var b =[...a]被equivelent到var b = [a[0], a[1], a[2]],不var b = [ a[0][0], a[1][0], a[2][0] ]

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

1

人,程序员真的很差,显示实际显示差异的例子。

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]的值不同,这意味着它的确是拷贝

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