…每个对象在同一个数组中也有对其他对象的引用?

当我第一次想到这个问题的时候,我就想到了

var clonedNodesArray = nodesArray.clone()

并搜索如何在JavaScript中克隆对象的信息。我确实在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中是否有可重用的方法来做到这一点?


当前回答

这取决于您使用的是Underscore.js还是Babel,下面是深度克隆数组的不同方式的基准测试。

https://jsperf.com/object-rest-spread-vs-clone/2

看起来巴别塔是最快的。

var x = babel({}, obj)

其他回答

我可能有一种简单的方法来做到这一点,而不需要做痛苦的递归,也不知道有关对象的所有细节。使用jQuery,只需使用jQuery $. tojson (myObjectArray)将对象转换为JSON,然后将JSON字符串计算回对象。砰!搞定了,搞定了!问题解决了。:)

var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));

jQuery:

var target = [];
$.each(source, function() {target.push($.extend({}, this));});

我想我们可以做到->

let a = [{name: "mike"}, {name: "ron"}];
let copy_a = [...a];

最简洁的浅拷贝解决方案:

array = array.map(obj => {
    return { ...obj };
});

这将生成[{a: 1}, {b: 2}]等内容的完全独立副本,而不是[{a: {b: 2}}, {b: {a: 1}}]。

使用structuredClone创建深度拷贝

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

array2 = structuredClone(array1);

然而,这个功能相对较新(Chrome 98, Firefox 94),目前只有大约85%的用户可以使用,所以它还没有准备好投入生产。

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

使用JSON.parse创建深度副本

一个通用的解决方案,即在对象数组中考虑所有可能的对象可能是不可能的。 也就是说,如果数组包含具有json序列化内容的对象(没有函数,没有Number。POSITIVE_INFINITY等)一个以性能为代价避免循环的简单方法就是这种纯香草式的单行解决方案。

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

or:

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

map/spread方法每次传递花费0.000466毫秒,JSON。解析和JSON。Stringify 0.014771毫秒每传递