Looking for ways to deep copy objects that contain nested and circular structures, neither of these (1, 2, 3, 4) had the perfect solution when it comes to circular references and prototypal inheritance.
I've written my own implementation here. Does it do the job well or count as a better solution?
/*
a function for deep cloning objects that contains other nested objects and circular structures.
objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
index (z)
|
|
|
|
|
| depth (x)
|_ _ _ _ _ _ _ _ _ _ _ _
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/...../
/................./
/..... /
/ /
/------------------
object length (y) /
*/
function deepClone(obj) {
var i = -1, //depth of the current object relative to the passed 'obj'
j = 0; //number of the object's properties
var arr = new Array(); //3D array to store the references to objects
return clone(obj, arr, i, j);
}
function clone(obj, arr, i ,j){
if (typeof obj !== "object") {
return obj;
}
var result = Object.create(Object.getPrototypeOf(obj)); //inherit the prototype of the original object
if(result instanceof Array){
result.length = Object.keys(obj).length;
}
i++; //depth is increased because we entered an object here
j = Object.keys(obj).length; //native method to get the number of properties in 'obj'
arr[i] = new Array(); //this is the x-axis, each index here is the depth
arr[i][j] = new Array(); //this is the y-axis, each index is the length of the object (aka number of props)
//start the depth at current and go down, cyclic structures won't form on depths more than the current one
for(var depth = i; depth >= 0; depth--){
//loop only if the array at this depth and length already have elements
if(arr[depth][j]){
for(var index = 0; index < arr[depth][j].length; index++){
if(obj === arr[depth][j][index]){
return obj;
}
}
}
}
arr[i][j].push(obj); //store the object in the array at the current depth and length
for (var prop in obj) {
result[prop] = clone(obj[prop], arr, i, j);
}
return result;
}