2

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;
}
Community
  • 1
  • 1
yazjisuhail
  • 357
  • 3
  • 6
  • Have you tried the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm)? – Ja͢ck Nov 12 '14 at 01:18
  • @Ja͢ck had a glance at that before. I believe it doesn't deal with circular structures, right? – yazjisuhail Nov 12 '14 at 01:21
  • plus, you need to manually implement the special cases (e.g. Date, Array, etc.) – yazjisuhail Nov 12 '14 at 01:22
  • 1
    Right in the first paragraph the page that describes the structured clone algorithm mentions cyclic graphs. Basically this problem is the well studied graph traversal problem. – akonsu Nov 12 '14 at 01:30
  • @akonsu I was reading through its pseudo [implementation](http://www.w3.org/TR/html5/infrastructure.html#safe-passing-of-structured-data). Which one you think would be faster? 3D array, as I approached it, or a map, as they approached? – yazjisuhail Nov 12 '14 at 01:42

1 Answers1

0

Can you try the below simple logic. Convert js object into new String and again convert as object.

E.g:

var car = {type:"Fiat", model:"500", color:"white"};
var cloneStr = new String(JSON.stringify(car));
var carClone = JSON.parse(cloneStr);
carClone.type = "Maruthi";
alert(JSON.stringify(car)) ;
alert(JSON.stringify(carClone)) ;
ARUN KUMAR
  • 46
  • 4