loading gif

Copying objects with JavaScript

Author: Gokan EKINCI
First publication date: 2015-12-27
License: CC BY-NC-SA

Goal: Making a perfect copy (or clone) of an object

Constraints:

Let's create a Foo type object :

function Foo(levelName, obj){
    this.levelName = levelName;
    this.deep = obj; 
}

Foo.prototype.method1 = function(){
    console.log("This method works !");
}

var originalObject = new Foo("Level 1", 
  new Foo("Level 2", 
    new Foo("Level 3", null)
  )
);

console.log(originalObject.levelName);            // Level 1
console.log(originalObject.deep.levelName);       // Level 2
console.log(originalObject.deep.deep.levelName);  // Level 3

Known solutions for copying objects:

ES6
var copy = Object.assign({}, originalObject);
jQuery (Mod 1)
var copy = jQuery.extend({}, originalObject);
jQuery (Mod 2)
var copy = jQuery.extend(true, {}, originalObject);
JSON
var copy = JSON.parse(JSON.stringify(originalObject));

My simple solution (may not work with an old version of Internet Explorer, should work with IE11) :

function clone(originalObject){
    if((typeof originalObject !== 'object') || originalObject === null){
        throw new TypeError("originalObject parameter must be an object which is not null");
    }

    var deepCopy = JSON.parse(JSON.stringify(originalObject));

    // A little recursivity
    function deepProto(originalObject, deepCopy){
        deepCopy.__proto__ = Object.create(originalObject.constructor.prototype);
        for(var attribute in originalObject){
            if(typeof originalObject[attribute] === 'object' && originalObject[attribute] !== null){
                deepProto(originalObject[attribute], deepCopy[attribute]);
            }
        }
    }
    deepProto(originalObject, deepCopy);

    return deepCopy;
}

var copy = clone(originalObject);

Deep-copy test :

console.log(copy.levelName);
console.log(copy.deep.levelName);
console.log(copy.deep.deep.levelName);
console.log(originalObject.deep === copy.deep);
console.log(originalObject.deep.deep === copy.deep.deep);
ES6 output
Level 1
Level 2
Level 3
true
true
=> No deep-copy :-(
jQuery (Mod 1) output
Level 1
Level 2
Level 3
true
true
=> No deep-copy :-(
jQuery (Mod 2) output
Level 1
Level 2
Level 3
true
true
=> No deep-copy :-(
JSON output
Level 1
Level 2
Level 3
false
false
=> Deep-copy :-)
My simple solution output
Level 1
Level 2
Level 3
false
false
=> Deep-copy :-)

Type test and method test:

console.log(copy.constructor.name);      // Type test1
console.log(copy.deep.constructor.name); // Type test2
copy.method1();                          // Method test1
copy.deep.method1();                     // Method test2
ES6 output
Object
Object
TypeError: copy.method1 is not a function
=> copy is not Foo type :-(
=> methods from Foo are not recognized :-(
jQuery (Mod 1) output
Object
Object
This method works !
This method works !
=> copy is not Foo type :-(
=> methods from Foo are recognized :-)
jQuery (Mod 2) output
Object
Object
This method works !
This method works !
=> copy is not Foo type :-(
=> methods from Foo are recognized :-)
JSON output
Object
Object
TypeError: copy.method1 is not a function
=> copy is not Foo type :-(
=> methods from Foo are not recognized :-(
My simple solution output
Foo
Foo
This method works !
This method works !
=> copy is Foo type :-)
=> methods from Foo are recognized :-)

Tests conclusion:

Deep-copy Method is recognized Method is recognized (deep level) Type Type (deep level)
ES6 Fail Fail Fail Fail Fail
jQuery (Mod 1) Fail Success Success Fail Fail
jQuery (Mod 2) Fail Success Success Fail Fail
JSON Success Fail Fail Fail Fail
My simple solution Success Success Success Success Success