Saturday, 23 April 2016

How do you clone an Array of Objects in Javascript?



...where each object also has references to other objects within the same array?



When I first came up with this problem I just though of something like



var clonedNodesArray = nodesArray.clone()



would exist and searched for info on how to clone objects in javascript. I did find a question on StackOverflow (answered by the very same @JohnResig) and he pointed out that with jQuery you could do



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


to clone an object. I tried this though, this only copies the references of the objects in the array. So if I



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



the value of both nodesArray[0] and clonedNodesArray[0] will turn out to be "green". Then I tried



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


which deep copies an Object, but I got "too much recursion" and "control " messages from both Firebug and Opera Dragonfly respectively.



How would you do it? Is this something that shouldn't even be done? Is there a reusable way of doing this in Javascript?


Answer




The issue with your shallow copy is that all the objects aren't cloned. While the references to each object are unique in each array, once you ultimately grab onto it you're dealing with the same object as before. There is nothing wrong with the way you cloned it... the same result would occur using Array.slice().



The reason your deep copy is having problems is because you're ending up with circular object references. Deep will go as deep as it can go, and if you've got a circle, it'll keep going infinitely until the browser faints.



If the data structure cannot be represented as a directed acyclic graph, then I'm not sure you're going to be able to find an all-purpose method for deep cloning. Cyclic graphs provide many tricky corner cases, and since it's not a common operation I doubt anyone has written a full solution (if it's even possible - it might not be! But I have no time to try to write a rigorous proof now.). I found some good comments on the issue on this page.



If you need a deep copy of an Array of Objects with circular references I believe you're going to have to code your own method to handle your specialized data structure, such that it is a multi-pass clone:




  1. On round one, make a clone of all objects that don't reference other objects in the array. Keep a track of each object's origins.


  2. On round two, link the objects together.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...