来自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中的数组复制到b中一样。我尝试在这里添加另一个维度到数组:https://repl.it/HKOq/2和事情仍然按预期工作。
那么,为什么spread语法不适合复制多维数组呢?
我很感激任何帮助。
编辑:
阅读estus和vol7ron的答案帮助我弄清楚了事情。基本上,正如estus指出的那样,技术上只有数组内部的数组,而不是多维数组。
正如vol7ron所解释的那样,只有数组的第一层被复制,因此内存中的对象对于任何进一步嵌套的元素都保持不变。
我还错误地怀疑使用spread语法的行为应该与slice操作符有任何不同
5条答案
按热度按时间wlp8pajw1#
伙计,程序员真的很不擅长展示实际显示差异的示例。
该输出:
注意到什么可疑的东西了吗?两个数组
[0][0][0]
的值都已更改。这意味着两个数组中位于[0][0][0]
处的对象被 * 引用 * 到同一个对象,而不是 * 副本 *。但是[1]
的值不同,这意味着它确实是一个 * 副本 *。2guxujil2#
数组是对象,
[...a]
创建a
数组对象的浅副本。对于语言本身来说,没有多维数组--一个数组中有另一个数组。包含数组、普通对象、函数还是原语都没有关系。对于基元,它们的值将被复制。否则,将复制对对象的引用。这是什么
这与Object.assign()和Objectspread操作符的情况相同
部分指。
关于
上面的代码示例的工作原理与使用.slice()方法将a中的数组复制到b中一样
确实如此这是写
a.slice()
或[].concat(a)
的更简洁的方法。但有一个例外。ES6 rest操作符(以及Array.from(a)
)对所有可迭代对象都同样有效,而不仅仅是数组。对于对象的deep副本,ES6没有提供任何新的内容,对象(数组)应该手动递归复制。为了解决所有问题,使用经过验证的第三方帮助函数仍然是有意义的,例如Lodash
cloneDeep
。dced5bon3#
不为内部数组元素创建新数组(对于多维数组):
它的工作方式类似于
slice()
,因此您必须遍历数组并为每个维度创建新数组。这里有一个简单的例子:nkhmeac64#
因此,这个例子试图传达的是,
var b = [...a];
不会展开a
的内部数组(例如b = [1,2,3]
),而是b
将是[[1],[2],[3]]
。所以b.shift()
删除并返回b
的第一个元素[1]
,然后第二个shift()
从返回的数组中删除1
。一句话,...
只能到达 spreaded 数组的一级,例如:var b =[...a]
等同于var b = [a[0], a[1], a[2]]
,而不是本例中的var b = [ a[0][0], a[1][0], a[2][0] ]
kq0g1dla5#
JS Vanilla中有一个structuredClone()函数。请查看以下地址的文档:https://developer.mozilla.org/en-US/docs/Web/API/structuredClone。这可用于创建深层副本。