javascript - 如何在 JavaScript 中克隆对象数组?

标签 javascript

...其中每个对象还引用同一数组中的其他对象?

当我第一次想到这个问题时,我只是想到了类似的东西

var clonedNodesArray = nodesArray.clone()

将存在并搜索有关如何在 JavaScript 中克隆对象的信息。我确实找到了 a question在 Stack Overflow 上(由同一个@JohnResig 回答),他指出使用 jQuery 你可以做到

var clonedNodesArray = jQuery.extend({}, nodesArray);

克隆一个对象。不过我试过了,这只会复制数组中对象的引用。所以如果我

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

nodesArray[0] 和 clonedNodesArray[0] 的值都将变为“绿色”。然后我试了一下

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

它深度复制了一个对象,但我从两个 Firebug 收到了“太多递归”和“控制堆栈溢出”消息和 Opera Dragonfly分别。

你会怎么做?这是不该做的事吗?在 JavaScript 中是否有可重复使用的方法?

最佳答案

使用 structuredClone 创建深拷贝

在 JavaScript 中深度复制数组的现代方法是使用 structuredClone :

array2 = structuredClone(array1);

不过这个函数比较新(Chrome 98,Firefox 94),是currently only available大约 85% 的用户,因此在没有 polyfill 的情况下还不能用于生产。

作为替代方案,您可以使用下面一种受良好支持的基于 JSON 的解决方案。

使用 JSON.parse 创建深拷贝

一个通用的解决方案可能无法解决对象数组中所有可能的对象。 也就是说,如果您的数组包含具有 JSON 可序列化内容的对象(没有函数,没有 Number.POSITIVE_INFINITY 等),一种以性能成本为代价避免循环的简单方法就是这种纯 Vanilla 方法-线解决方案。

let clonedArray = JSON.parse(JSON.stringify(nodesArray))

总结一下下面的评论,这种方法的主要优点是它还克隆了数组的内容,而不仅仅是数组本身。主要缺点是它只能处理 JSON 序列化内容,而且它的性能比 spread 方法慢 30 倍。

如果数组中有浅层对象,并且 IE6 可以接受,更好的方法是结合使用扩展运算符和 .map 数组运算符。对于两层深的情况(如下面附录中的数组):

clonedArray = nodesArray.map(a => {return {...a}})

原因有两个:1) 它要快得多(请参阅下面的基准比较)并且它还允许数组中的任何有效对象。

*附录: 性能量化基于将此对象数组克隆一百万次:

 [{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic1.jpg?raw=true', id: '1', isFavorite: false}, {url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic2.jpg?raw=true', id: '2', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic3.jpg?raw=true', id: '3', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic4.jpg?raw=true', id: '4', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic5.jpg?raw=true', id: '5', isFavorite: true},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic6.jpg?raw=true', id: '6', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic7.jpg?raw=true', id: '7', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic8.jpg?raw=true', id: '8', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic9.jpg?raw=true', id: '9', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic10.jpg?raw=true', id: '10', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic11.jpg?raw=true', id: '11', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic12.jpg?raw=true', id: '12', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic13.jpg?raw=true', id: '13', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic14.jpg?raw=true', id: '14', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic15.jpg?raw=true', id: '15', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic16.jpg?raw=true', id: '16', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic17.jpg?raw=true', id: '17', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic18.jpg?raw=true', id: '18', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic19.jpg?raw=true', id: '19', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic20.jpg?raw=true', id: '20', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic21.jpg?raw=true', id: '21', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic22.jpg?raw=true', id: '22', isFavorite: false},{url: 'https://github.com/bobziroll/scrimba-react-bootcamp-images/blob/master/pic23.jpg?raw=true', id: '23', isFavorite: false}]

要么使用:

let clonedArray = JSON.parse(JSON.stringify(nodesArray))

或:

clonedArray = nodesArray.map(a => {return {...a}})

map/spread 方法每次通过 0.000466 毫秒,而 JSON.parse 和 JSON.stringify 每次通过 0.014771 毫秒。*

关于javascript - 如何在 JavaScript 中克隆对象数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57972068/

相关文章:

javascript - (Javascript)为什么捕获没有捕获到拒绝?

javascript - Jquery改变偶类中每个下一个偶数tr的颜色

javascript - 评估函数中的JS无法执行

javascript - 找不到模块 : Error: Can't resolve 'dropzone'

javascript - CasperJS 不适用于 Centos 服务器,但适用于 Windows 10

javascript - 获取 RadComboBox 客户端旧的勾选项

javascript - 如何通过填写文本字段来检查单选按钮?

javascript - 获取 ng-repeat 的匹配 ng-if 的数量

javascript - 当点击最后一张幻灯片上的下一页时,转到 WordPress 中的下一页?

javascript - 在 IE8 上获取访问被拒绝错误