[javascript] How to Deep clone in javascript

How do you deep clone a JavaScript object?

I know there are various functions based on frameworks like JSON.parse(JSON.stringify(o)) and $.extend(true, {}, o) but I don't want to use a framework like that.

What is the most elegant or efficient way to create a deep clone.

We do care about edge cases like cloning array's. Not breaking prototype chains, dealing with self reference.

We don't care about supporting copying of DOM objects and like because .cloneNode exists for that reason.

As I mainly want to use deep clones in node.js using ES5 features of the V8 engine is acceptable.

[Edit]

Before anyone suggests let me mention there is a distinct difference between creating a copy by prototypically inheriting from the object and cloning it. The former makes a mess of the prototype chain.

[Further Edit]

After reading your answer I came to the annoying discovery that cloning entire objects is a very dangerous and difficult game. Take for example the following closure based object

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

Is there any way to write a clone function that clones the object, has the same state at time of cloning but cannot alter the state of o without writing a JS parser in JS.

There should be no real world need for such a function anymore. This is mere academic interest.

This question is related to javascript

The answer is


We can utilize recursion for making deepCopy. It can create copy of array, object, array of object, object with function. if you want, you can add function for other type of data structure like map etc.

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

Lo-Dash, now a superset of Underscore.js, has a couple of deep clone functions:

From an answer of the author himself:

lodash underscore build is provided to ensure compatibility with the latest stable version of Underscore.


I noticed that Map should require special treatment, thus with all suggestions in this thread, code will be:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

var newDate = new Date(this.oldDate); I was passing oldDate to function and generating newDate from this.oldDate, but it was changing this.oldDate also.So i used that solution and it worked.


There should be no real world need for such a function anymore. This is mere academic interest.

As purely an exercise, this is a more functional way of doing it. It's an extension of @tfmontague's answer as I'd suggested adding a guard block there. But seeing as I feel compelled to ES6 and functionalise all the things, here's my pimped version. It complicates the logic as you have to map over the array and reduce over the object, but it avoids any mutations.

_x000D_
_x000D_
const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))
_x000D_
_x000D_
_x000D_


The JSON.parse(JSON.stringify()) combination to deep copy Javascript objects is an ineffective hack, as it was meant for JSON data. It does not support values of undefined or function () {}, and will simply ignore them (or null them) when "stringifying" (marshalling) the Javascript object into JSON.

A better solution is to use a deep copy function. The function below deep copies objects, and does not require a 3rd party library (jQuery, LoDash, etc).

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

The below function is most efficient way to deep clone javascript objects.

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

My solution, deep clones objects, arrays and functions.

let superClone = (object) => {
  let cloning = {};

  Object.keys(object).map(prop => {
     if(Array.isArray(object[prop])) {
        cloning[prop] = [].concat(object[prop])
    } else if(typeof  object[prop] === 'object') {
      cloning[prop] = superClone(object[prop])
    } else cloning[prop] = object[prop]
  })

  return cloning
}

example

let obj = {
  a: 'a',
  b: 'b',
  c: {
    deep: 'try and copy me',
    d: {
      deeper: 'try me again',
      callDeeper() {
       return this.deeper
     }
    },
    arr: [1, 2, 3]
  },
  hi() {
    return this.a
  }
};


const cloned = superClone(obj)
obj.a = 'A' 
obj.c.deep = 'i changed'
obj.c.arr = [45,454]
obj.c.d.deeper = 'i changed'

console.log(cloned) // unchanged object

If your objects contain methods don't use JSON to deep clone, JSON deep cloning doesn't clone methods.

If you take a look at this, object person2 only clones the name, not person1's greet method.


const person1 = {
  name: 'John',
  greet() {
    return `HI, ${this.name}`
  }
}
 
const person2 = JSON.parse(JSON.stringify(person1))
 
console.log(person2)  // { name: 'John' }


Avoid use this method

let cloned = JSON.parse(JSON.stringify(objectToClone));

Why? this method will convert 'function,undefined' to null

const myObj = [undefined, null, function () {}, {}, '', true, false, 0, Symbol];

const IsDeepClone = JSON.parse(JSON.stringify(myObj));

console.log(IsDeepClone); //[null, null, null, {…}, "", true, false, 0, null]

try to use deepClone function.There are several above


Here is an ES6 function that will also work for objects with cyclic references:

_x000D_
_x000D_
function deepClone(obj, hash = new WeakMap()) {_x000D_
    if (Object(obj) !== obj) return obj; // primitives_x000D_
    if (hash.has(obj)) return hash.get(obj); // cyclic reference_x000D_
    const result = obj instanceof Set ? new Set(obj) // See note about this!_x000D_
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => _x000D_
                                        [key, deepClone(val, hash)])) _x000D_
                 : obj instanceof Date ? new Date(obj)_x000D_
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)_x000D_
                 // ... add here any specific treatment for other classes ..._x000D_
                 // and finally a catch-all:_x000D_
                 : obj.constructor ? new obj.constructor() _x000D_
                 : Object.create(null);_x000D_
    hash.set(obj, result);_x000D_
    return Object.assign(result, ...Object.keys(obj).map(_x000D_
        key => ({ [key]: deepClone(obj[key], hash) }) ));_x000D_
}_x000D_
_x000D_
// Sample data_x000D_
var p = {_x000D_
  data: 1,_x000D_
  children: [{_x000D_
    data: 2,_x000D_
    parent: null_x000D_
  }]_x000D_
};_x000D_
p.children[0].parent = p;_x000D_
_x000D_
var q = deepClone(p);_x000D_
_x000D_
console.log(q.children[0].parent.data); // 1
_x000D_
_x000D_
_x000D_

A note about Sets and Maps

How to deal with the keys of Sets and Maps is debatable: those keys are often primitives (in which case there is no debate), but they can also be objects. In that case the question becomes: should those keys be cloned?

One could argue that this should be done, so that if those objects are mutated in the copy, the objects in the original are not affected, and vice versa.

On the other hand one would want that if a Set/Map has a key, this should be true in both the original and the copy -- at least before any change is made to either of them. It would be strange if the copy would be a Set/Map that has keys that never occurred before (as they were created during the cloning process): surely that is not very useful for any code that needs to know whether a given object is a key in that Set/Map or not.

As you notice, I am more of the second opinion: the keys of Sets and Maps are values (maybe references) that should remain the same.

Such choices will often also surface with other (maybe custom) objects. There is no general solution, as much depends on how the cloned object is expected to behave in your specific case.


This one, using circular reference, works for me

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

The Underscore.js contrib library library has a function called snapshot that deep clones an object

snippet from the source:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

once the library is linked to your project, invoke the function simply using

_.snapshot(object);

my addition to all the answers

function deepCopy(arr) {
  if (typeof arr !== 'object') return arr
  if (Array.isArray(arr)) return [...arr].map(deepCopy)
  for (const prop in arr) 
    copy[prop] = deepCopy(arr[prop])
  return copy
}

Very simple way, maybe too simple:

var cloned = JSON.parse(JSON.stringify(objectToClone));

This is the deep cloning method I use, I think it Great, hope you make suggestions

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

This works for arrays, objects and primitives. Doubly recursive algorithm that switches between two traversal methods:

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

This solution will avoid recursion problems when using [...target] or {...target}

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}

As others have noted on this and similar questions, cloning an "object", in the general sense, is dubious in JavaScript.

However, there is a class of objects, which I call "data" objects, that is, those constructed simply from { ... } literals and/or simple property assignments or deserialized from JSON for which it is reasonable to want to clone. Just today I wanted to artificially inflate data received from a server by 5x to test what happens for a large data set, but the object (an array) and its children had to be distinct objects for things to function correctly. Cloning allowed me to do this to multiply my data set:

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

The other place I often end up cloning data objects is for submitting data back to the host where I want to strip state fields from the object in the data model before sending it. For example, I might want to strip all fields starting with "_" from the object as it is cloned.

This is the code I ended up writing to do this generically, including supporting arrays and a selector to choose which members to clone (which uses a "path" string to determine context):

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

The simplest reasonable deep-clone solution, assuming a non-null root object and with no member selection is:

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

Use immutableJS

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

Or lodash/merge

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }