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

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

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中是否有可重用的方法来做到这一点?


当前回答

正如Daniel Lew提到的,循环图有一些问题。如果我有这个问题,我要么向有问题的对象添加特殊的clone()方法,要么记住我已经复制了哪些对象。

我会用一个变量copyCount来做,它在你每次复制代码时增加1。copyCount小于当前复制进程的对象将被复制。如果不是,则应该引用已经存在的副本。这就需要从原文链接到副本。

还有一个问题:内存。如果您从一个对象引用到另一个对象,那么浏览器很可能无法释放这些对象,因为它们总是从某个地方引用。您必须进行第二次传递,将所有复制引用设置为Null。(如果你这样做,你不必有一个copyCount,但一个布尔iscopy就足够了,因为你可以在第二步重置值。)

其他回答

对于克隆对象,我只是建议ECMAScript 6 reduce():

const newArray = myArray.reduce((array, element) => array.push(Object.assign({}, element)), []);

但坦白说,我更喜欢恐龙的答案。我只是把这个版本放在这里作为另一个选择,但就我个人而言,我将使用map(),因为恐龙建议。

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

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

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

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

看起来巴别塔是最快的。

var x = babel({}, obj)

数组中。Slice可以用来复制一个数组或数组的一部分…

这将与字符串和数字工作..-改变一个数组中的字符串不会影响另一个数组-但对象仍然只是通过引用复制,所以改变一个数组中引用的对象会影响另一个数组。

下面是一个JavaScript撤销管理器的示例,它可能对此很有用:http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx

jQuery扩展工作正常。你只需要指定你克隆的是一个数组而不是一个对象(注意extend方法的参数是[]而不是{}):

var clonedNodesArray = jQuery.extend([], nodesArray);