By jschrab


2008-09-23 16:26:09 8 Comments

What is the most efficient way to clone a JavaScript object? I've seen obj = eval(uneval(o)); being used, but that's non-standard and only supported by Firefox.

I've done things like obj = JSON.parse(JSON.stringify(o)); but question the efficiency.

I've also seen recursive copying functions with various flaws.
I'm surprised no canonical solution exists.

30 comments

@John Resig 2008-09-23 18:09:37

Native deep cloning

It's called "structured cloning", works experimentally in Node 11 and later, and hopefully will land in browsers. See this answer for more details.

Fast cloning with data loss - JSON.parse/stringify

If you do not use Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types within your object, a very simple one liner to deep clone an object is:

JSON.parse(JSON.stringify(object))

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

See Corban's answer for benchmarks.

Reliable cloning using a library

Since cloning objects is not trivial (complex types, circular references, function etc.), most major libraries provide function to clone objects. Don't reinvent the wheel - if you're already using a library, check if it has an object cloning function. For example,

ES6

For completeness, note that ES6 offers two shallow copy mechanisms: Object.assign() and the spread syntax. which copies values of all enumerable own properties from one object to another. For example:

var A1 = {a: "2"};
var A2 = Object.assign({}, A1);
var A3 = {...A1};  // Spread Syntax

@Tính Ngô Quang 2018-08-08 08:17:31

Deep copying objects in JavaScript (I think the best and the simplest)

1. Using JSON.parse(JSON.stringify(object));

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = JSON.parse(JSON.stringify(obj));
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

2.Using created method

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}
var newObj = cloneObject(obj);
obj.b.c = 20;

console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

3. Using Lo-Dash's _.cloneDeep link lodash

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 2 } } 

4. Using Object.assign() method

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

BUT WRONG WHEN

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = Object.assign({}, obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// Note: Properties on the prototype chain and non-enumerable properties cannot be copied.

5.Using Underscore.js _.clone link Underscore.js

var obj = { 
  a: 1,
  b: 2
}

var newObj = _.clone(obj);
obj.b = 20;
console.log(obj); // { a: 1, b: 20 }
console.log(newObj); // { a: 1, b: 2 }  

BUT WRONG WHEN

var obj = { 
  a: 1,
  b: { 
    c: 2
  }
}

var newObj = _.cloneDeep(obj);
obj.b.c = 20;
console.log(obj); // { a: 1, b: { c: 20 } }
console.log(newObj); // { a: 1, b: { c: 20 } } --> WRONG
// (Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated.)

JSBEN.CH Performance Benchmarking Playground 1~3 http://jsben.ch/KVQLd Performance Deep copying objects in JavaScript

@Roymunson 2018-08-15 20:23:28

Object.assign() does not perform a deep copy

@jcollum 2018-10-30 23:00:19

you should add benchmarks for these; that would be very helpful

@hugogogo 2019-03-24 23:54:35

when i used the "created method" on an object containing an array i was unable to use pop() or splice() on it, i don't understand why ? let data = {title:["one", "two"]}; let tmp = cloneObject(data); tmp.title.pop(); it throw: TypeError: tmp.title.pop is not a function (of course pop() works fine if i just do let tmp = data; but then i can't modify tmp without affecting data)

@kenanyildiz 2019-12-10 07:20:58

Hey, your last example is wrong. In my opinion, you must use _clone and not _cloneDeep for the wrong example.

@Toivo Säwén 2019-12-18 14:06:07

This created method (2.) won't work for arrays, will it?

@Corban Brook 2011-03-17 19:19:55

Checkout this benchmark: http://jsben.ch/#/bWfk9

In my previous tests where speed was a main concern I found

JSON.parse(JSON.stringify(obj))

to be the slowest way to deep clone an object (it is slower than jQuery.extend with deep flag set true by 10-20%).

jQuery.extend is pretty fast when the deep flag is set to false (shallow clone). It is a good option, because it includes some extra logic for type validation and doesn't copy over undefined properties, etc., but this will also slow you down a little.

If you know the structure of the objects you are trying to clone or can avoid deep nested arrays you can write a simple for (var i in obj) loop to clone your object while checking hasOwnProperty and it will be much much faster than jQuery.

Lastly if you are attempting to clone a known object structure in a hot loop you can get MUCH MUCH MORE PERFORMANCE by simply in-lining the clone procedure and manually constructing the object.

JavaScript trace engines suck at optimizing for..in loops and checking hasOwnProperty will slow you down as well. Manual clone when speed is an absolute must.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

Beware using the JSON.parse(JSON.stringify(obj)) method on Date objects - JSON.stringify(new Date()) returns a string representation of the date in ISO format, which JSON.parse() doesn't convert back to a Date object. See this answer for more details.

Additionally, please note that, in Chrome 65 at least, native cloning is not the way to go. According to JSPerf, performing native cloning by creating a new function is nearly 800x slower than using JSON.stringify which is incredibly fast all the way across the board.

Update for ES6

If you are using Javascript ES6 try this native method for cloning or shallow copy.

Object.assign({}, obj);

@Ankur Kedia 2019-08-03 16:36:52

This is my solution without using any library or native javascript function.

function deepClone(obj) {
  if (typeof obj !== "object") {
    return obj;
  } else {
    let newObj =
      typeof obj === "object" && obj.length !== undefined ? [] : {};
    for (let key in obj) {
      if (key) {
        newObj[key] = deepClone(obj[key]);
      }
    }
    return newObj;
  }
}

@Ian 2019-08-21 17:23:48

Careful... const o = {}; o.a = o; deepClone(o); -> recursion error.

@KRIPA SHANKAR JHA 2019-05-28 06:17:12

Object.assign({},sourceObj) only clones the object if their property is not having reference type key. ex

obj={a:"lol",b:["yes","no","maybe"]}
clonedObj = Object.assign({},obj);

clonedObj.b.push("skip")// changes will reflected to the actual obj as well because of its reference type.
obj.b //will also console => yes,no,maybe,skip

So for the deep cloning is not possible to achieve in this way.

The best solution that works is

var obj = Json.stringify(yourSourceObj)
var cloned = Json.parse(obj);

@Kamyar 2019-05-19 12:22:39

My scenario was a bit different. I had an object with nested objects as well as functions. Therefore, Object.assign() and JSON.stringify() were not solutions to my problem. Using third-party libraries was not an option for me neither.

Hence, I decided to make a simple function to use built-in methods to copy an object with its literal properties, its nested objects, and functions.

let deepCopy = (target, source) => {
    Object.assign(target, source);
    // check if there's any nested objects
    Object.keys(source).forEach((prop) => {
        /**
          * assign function copies functions and
          * literals (int, strings, etc...)
          * except for objects and arrays, so:
          */
        if (typeof(source[prop]) === 'object') {
            // check if the item is, in fact, an array
            if (Array.isArray(source[prop])) {
                // clear the copied referenece of nested array
                target[prop] = Array();
                // iterate array's item and copy over
                source[prop].forEach((item, index) => {
                    // array's items could be objects too!
                    if (typeof(item) === 'object') {
                        // clear the copied referenece of nested objects
                        target[prop][index] = Object();
                        // and re do the process for nested objects
                        deepCopy(target[prop][index], item);
                    } else {
                        target[prop].push(item);
                    }
                });
            // otherwise, treat it as an object
            } else {
                // clear the copied referenece of nested objects
                target[prop] = Object();
                // and re do the process for nested objects
                deepCopy(target[prop], source[prop]);
            }
        }
    });
};

Here's a test code:

let a = {
    name: 'Human', 
    func: () => {
        console.log('Hi!');
    }, 
    prop: {
        age: 21, 
        info: {
            hasShirt: true, 
            hasHat: false
        }
    },
    mark: [89, 92, { exam: [1, 2, 3] }]
};

let b = Object();

deepCopy(b, a);

a.name = 'Alien';
a.func = () => { console.log('Wassup!'); };
a.prop.age = 1024;
a.prop.info.hasShirt = false;
a.mark[0] = 87;
a.mark[1] = 91;
a.mark[2].exam = [4, 5, 6];

console.log(a); // updated props
console.log(b);

For efficiency-related concerns, I believe this is the simplest and most efficient solution to the problem I had. I would appreciate any comments on this algorithm that could make it more efficient.

@Shidersz 2019-04-16 05:33:51

With the proposal of the new method Object.fromEntries() that is supported on newer versions of some browsers (reference). I want to contribute with the next recursive approach:

const obj = {
  key1: {key11: "key11", key12: "key12", key13: {key131: 22}},
  key2: {key21: "key21", key22: "key22"},
  key3: "key3",
  key4: [1,2,3, {key: "value"}]
}

const cloneObj = (obj) =>
{
    if (Object(obj) !== obj)
       return obj;
    else if (Array.isArray(obj))
       return obj.map(cloneObj);

    return Object.fromEntries(Object.entries(obj).map(
        ([k,v]) => ([k, cloneObj(v)])
    ));
}

// Clone the original object.
let newObj = cloneObj(obj);

// Make changes on the original object.
obj.key1.key11 = "TEST";
obj.key3 = "TEST";
obj.key1.key13.key131 = "TEST";
obj.key4[1] = "TEST";
obj.key4[3].key = "TEST";

// Display both objects on the console.
console.log("Original object: ", obj);
console.log("Cloned object: ", newObj);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

@Mystical 2019-02-05 01:11:56

How about merging the keys of the object with its values?

function deepClone(o) {
    var keys = Object.keys(o);
    var values = Object.values(o);

    var clone = {};

    keys.forEach(function(key, i) {
        clone[key] = typeof values[i] == 'object' ? Object.create(values[i]) : values[i];
    });

    return clone;
}

Note: This method doesn't necessarily make shallow copies, but it only copies with the depth of one inner-object, meaning that when you are given something like {a: {b: {c: null}}}, it will only clone the objects that are directly inside of them, so deepClone(a.b).c is technically a reference to a.b.c, while deepClone(a).b is a clone, not a reference.

@shakthi nagaraj 2019-02-05 13:46:15

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}

use the following method instead of JSON.parse(JSON.stringify(obj)) because it is slower than the following method

How do I correctly clone a JavaScript object?

@TRUMP says to NAZIS - STAND BY 2012-06-06 14:59:04

Structured Cloning

The HTML standard includes an internal structured cloning/serialization algorithm that can create deep clones of objects. It is still limited to certain built-in types, but in addition to the few types supported by JSON it also supports Dates, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays, and probably more in the future. It also preserves references within the cloned data, allowing it to support cyclical and recursive structures that would cause errors for JSON.

Support in Node.js: Experimental 🙂

The v8 module in Node.js currently (as of Node 11) exposes the structured serialization API directly, but this functionality is still marked as "experimental", and subject to change or removal in future versions. If you're using a compatible version, cloning an object is as simple as:

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Direct Support in Browsers: Maybe Eventually? 😐

Browsers do not currently provide a direct interface for the structured cloning algorithm, but a global structuredClone() function has been discussed in whatwg/html#793 on GitHub. As currently proposed, using it for most purposes would be as simple as:

const clone = structuredClone(original);

Unless this is shipped, browsers' structured clone implementations are only exposed indirectly.

Asynchronous Workaround: Usable. 😕

The lower-overhead way to create a structured clone with existing APIs is to post the data through one port of a MessageChannels. The other port will emit a message event with a structured clone of the attached .data. Unfortunately, listening for these events is necessarily asynchronous, and the synchronous alternatives are less practical.

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

Example Use:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

Synchronous Workarounds: Awful! 🤢

There are no good options for creating structured clones synchronously. Here are a couple of impractical hacks instead.

history.pushState() and history.replaceState() both create a structured clone of their first argument, and assign that value to history.state. You can use this to create a structured clone of any object like this:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

Example Use:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

Though synchronous, this can be extremely slow. It incurs all of the overhead associated with manipulating the browser history. Calling this method repeatedly can cause Chrome to become temporarily unresponsive.

The Notification constructor creates a structured clone of its associated data. It also attempts to display a browser notification to the user, but this will silently fail unless you have requested notification permission. In case you have the permission for other purposes, we'll immediately close the notification we've created.

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

Example Use:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();

@TRUMP says to NAZIS - STAND BY 2013-05-06 03:11:03

@rynah I just looked through the spec again and you're right: the history.pushState() and history.replaceState() methods both synchronously set history.state to a structured clone of their first argument. A little weird, but it works. I'm updating my answer now.

@Fardin K. 2014-07-31 23:34:51

This is just so wrong! That API is not meant to be used this way.

@Justin L. 2014-08-14 18:37:25

As the guy who implemented pushState in Firefox, I feel an odd mix of pride and revulsion at this hack. Well done, guys.

@Shishir Arora 2019-07-03 20:06:56

pushState or Notification hack does not work for some object types like Function

@ADJenks 2020-07-10 21:39:43

@ShishirArora You're right, I just tried it, it throws a 'Uncaught DOMException: The object could not be cloned.' This is also true for the Notification hack.

@chandan gupta 2018-11-05 09:43:14

In JavaScript, you can write your deepCopy method like

function deepCopy(src) {
  let target = Array.isArray(src) ? [] : {};
  for (let prop in src) {
    let value = src[prop];
    if(value && typeof value === 'object') {
      target[prop] = deepCopy(value);
  } else {
      target[prop] = value;
  }
 }
    return target;
}

@shunryu111 2018-10-10 09:21:56

if you find yourself doing this type of thing regular ( eg- creating undo redo functionality ) it might be worth looking into Immutable.js

const map1 = Immutable.fromJS( { a: 1, b: 2, c: { d: 3 } } );
const map2 = map1.setIn( [ 'c', 'd' ], 50 );

console.log( `${ map1.getIn( [ 'c', 'd' ] ) } vs ${ map2.getIn( [ 'c', 'd' ] ) }` ); // "3 vs 50"

https://codepen.io/anon/pen/OBpqNE?editors=1111

@ConroyP 2008-09-23 16:38:51

If there wasn't any builtin one, you could try:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

@jschrab 2008-09-23 17:23:51

The JQuery solution will work for DOM elements but not just any Object. Mootools has the same limit. Wish they had a generic "clone" for just any object... The recursive solution should work for anything. It's probably the way to go.

@Andrew Arnott 2009-10-04 22:06:39

This function breaks if the object being cloned has a constructor that requires parameters. It seems like we can change it to "var temp = new Object()" and have it work in every case, no?

@limscoder 2011-09-14 15:53:31

Andrew, if you change it to var temp = new Object(), then your clone won't have the same prototype as the original object. Try using: 'var newProto = function(){}; newProto.prototype = obj.constructor; var temp = new newProto();'

@Matt Browne 2012-11-11 17:55:03

Similar to limscoder's answer, see my answer below on how to do this without calling the constructor: stackoverflow.com/a/13333781/560114

@virtualnobi 2013-11-11 08:34:37

For objects that contain references to sub-parts (i.e., networks of objects), this does not work: If two references point to the same sub-object, the copy contains two different copies of it. And if there are recursive references, the function will never terminate (well, at least not in the way you want it :-) For these general cases, you have to add a dictionary of objects already copied, and check whether you already copied it... Programming is complex when you use a simple language

@Peter Mortensen 2014-02-22 15:11:31

The link to Keith Deven's blog post is broken.

@Cihad Turhan 2014-03-27 10:08:22

@ConroyP this is not a healty solution in case of circular reference. jsfiddle.net/d3KcP

@Garet Claborn 2015-06-05 11:26:11

@CihadTurhan added a circular reference fix at jsfiddle.net/d3KcP/9. Note it will add a temporary property to cloned objects

@kofifus 2016-09-22 23:30:48

does not work for Event objects - constructor call fails

@Phil 2017-06-30 10:58:04

Fails for: clone({isActiveClone: false, isHijackingObjectKeysAGoodIdea: false })

@shoosh 2019-08-30 19:59:14

isActiveClone doesn't really solve all cycle problems. if an object as two references to the same object, it's going to get duplicated

@Arjun Nayak 2020-06-27 09:36:16

No need for any check, simply use below code. You'll get exact same copy. Simply paste below code in your browser console and see it for yourself. const sourceObject = {a: null, b: () => {console.log(1)}, c: [10,20], d: undefined, e: false, f: {g: {h: {j: {name: "arjun"}}}}}; const destinationObject = {}; for (let prop in sourceObject) { destinationObject[prop] = sourceObject[prop]; } console.log(destinationObject);

@Prasanth Jaya 2018-08-23 09:40:50

When your object is nested and it contains data object, other structured object or some property object, etc then using JSON.parse(JSON.stringify(object)) or Object.assign({}, obj) or $.extend(true, {}, obj) will not work. In that case use lodash. It is simple and easy..

var obj = {a: 25, b: {a: 1, b: 2}, c: new Date(), d: anotherNestedObject };
var A = _.cloneDeep(obj);

Now A will be your new cloned of obj without any references..

@Jinu Joseph Daniel 2018-07-16 07:58:04

Hope this helps.

function deepClone(obj) {
    /*
     * Duplicates an object 
     */

    var ret = null;
    if (obj !== Object(obj)) { // primitive types
        return obj;
    }
    if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { // string objecs
        ret = obj; // for ex: obj = new String("Spidergap")
    } else if (obj instanceof Date) { // date
        ret = new obj.constructor();
    } else
        ret = Object.create(obj.constructor.prototype);

    var prop = null;
    var allProps = Object.getOwnPropertyNames(obj); //gets non enumerables also


    var props = {};
    for (var i in allProps) {
        prop = allProps[i];
        props[prop] = false;
    }

    for (i in obj) {
        props[i] = i;
    }

    //now props contain both enums and non enums 
    var propDescriptor = null;
    var newPropVal = null; // value of the property in new object
    for (i in props) {
        prop = obj[i];
        propDescriptor = Object.getOwnPropertyDescriptor(obj, i);

        if (Array.isArray(prop)) { //not backward compatible
            prop = prop.slice(); // to copy the array
        } else
        if (prop instanceof Date == true) {
            prop = new prop.constructor();
        } else
        if (prop instanceof Object == true) {
            if (prop instanceof Function == true) { // function
                if (!Function.prototype.clone) {
                    Function.prototype.clone = function() {
                        var that = this;
                        var temp = function tmp() {
                            return that.apply(this, arguments);
                        };
                        for (var ky in this) {
                            temp[ky] = this[ky];
                        }
                        return temp;
                    }
                }
                prop = prop.clone();

            } else // normal object 
            {
                prop = deepClone(prop);
            }

        }

        newPropVal = {
            value: prop
        };
        if (propDescriptor) {
            /*
             * If property descriptors are there, they must be copied
             */
            newPropVal.enumerable = propDescriptor.enumerable;
            newPropVal.writable = propDescriptor.writable;

        }
        if (!ret.hasOwnProperty(i)) // when String or other predefined objects
            Object.defineProperty(ret, i, newPropVal); // non enumerable

    }
    return ret;
}

https://github.com/jinujd/Javascript-Deep-Clone

@Vikram K 2018-06-24 19:08:38

For a shallow copy there is a great, simple method introduced in ECMAScript2018 standard. It involves the use of Spread Operator :

let obj = {a : "foo", b:"bar" , c:10 , d:true , e:[1,2,3] };

let objClone = { ...obj };

I have tested it in Chrome browser, both objects are stored in different locations, so changing immediate child values in either will not change the other. Though (in the example) changing a value in e will effect both copies.

This technique is very simple and straight forward. I consider this a true Best Practice for this question once and for all.

@Taugenichts 2018-06-27 14:59:10

updating e in objClone will still update e in obj. This is still only a shallow copy. The question explicitly asks for a deep clone.

@mickro 2018-06-27 17:06:16

@Taugenichts... did you tested it? The method works perfectly. Spread_syntax Spread in object literals section

@Taugenichts 2018-06-27 17:35:46

yes, I tested it. run this code: objClone.e[4] = 5; console.log(obj.e); You will see obj.e being updated

@Lupus Ossorum 2018-06-29 21:24:06

Because both are stored in different locations merely means it is at least a shallow copy. Look at where obj.e and objClone.e are stored; you will find that they are stored in the same location.

@Vikram K 2018-07-10 09:29:16

Thanks a lot, [email protected] @Taugenichts for pointing this out. I tested it myself and found out what you guys identified here. But do you have any idea why the array still does not change memory, though ECMA2018 boasts of this as a feature.

@Taugenichts 2018-09-13 15:31:36

From mozilla's docs on it under Spread in object literals: "Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign()." - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

@Parabolord 2018-06-19 22:06:13

In my experience, a recursive version vastly outperforms JSON.parse(JSON.stringify(obj)). Here is a modernized recursive deep object copy function which can fit on a single line:

function deepCopy(obj) {
  return Object.keys(obj).reduce((v, d) => Object.assign(v, {
    [d]: (obj[d].constructor === Object) ? deepCopy(obj[d]) : obj[d]
  }), {});
}

This is performing around 40 times faster than the JSON.parse... method.

@Parabolord 2018-08-15 20:48:06

Pseudocode would be: for each key, assign its value to the same key in a new object (shallow copy). However if the value is of type Object (can't shallow copy), the function recursively calls itself with the value as an argument.

@zenw0lf 2019-08-24 22:30:55

Too bad it doesn't work right when the value is an array. But, shouldn't be too difficult to modify to get it to work for that case.

@codeMonkey 2018-03-26 17:42:48

ES 2017 example:

let objectToCopy = someObj;
let copyOfObject = {};
Object.defineProperties(copyOfObject, Object.getOwnPropertyDescriptors(objectToCopy));
// copyOfObject will now be the same as objectToCopy

@Takesi Tokugawa YD 2018-06-10 03:39:53

Thank you for the answer. I tried your approach, but unfortunately, it does not work. Because it could be some kind of mistake on my side, I ask you for check my example in JSFiddle and if it will be some mistake on my side, I'll vote up for your answer.

@codeMonkey 2018-06-10 03:50:01

When I run your fiddle, I get { foo: 1, bar: { fooBar: 22, fooBaz: 33, fooFoo: 11 }, baz: 3} and { foo: 1, bar: { fooBar: 22, fooBaz: 44, fooFoo: 11 }, baz: 4}. Is that not what you expect to happen?

@Takesi Tokugawa YD 2018-06-10 03:55:32

what you pasted is what I expected. I don't understand why, but I see fooBaz: 44 for both testObj2 and testObj3 in console... (screenshot)

@Nikita Malyschkin 2019-01-17 06:25:42

This is not a deep copy but a shallow copy. @GurebuBokofu

@tfmontague 2014-09-18 20:10:38

Deep copy by performance: Ranked from best to worst

  • Reassignment "=" (string arrays, number arrays - only)
  • Slice (string arrays, number arrays - only)
  • Concatenation (string arrays, number arrays - only)
  • Custom function: for-loop or recursive copy
  • jQuery's $.extend
  • JSON.parse (string arrays, number arrays, object arrays - only)
  • Underscore.js's _.clone (string arrays, number arrays - only)
  • Lo-Dash's _.cloneDeep

Deep copy an array of strings or numbers (one level - no reference pointers):

When an array contains numbers and strings - functions like .slice(), .concat(), .splice(), the assignment operator "=", and Underscore.js's clone function; will make a deep copy of the array's elements.

Where reassignment has the fastest performance:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

And .slice() has better performance than .concat(), http://jsperf.com/duplicate-array-slice-vs-concat/3

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

Deep copy an array of objects (two or more levels - reference pointers):

var arr1 = [{object:'a'}, {object:'b'}];

Write a custom function (has faster performance than $.extend() or JSON.parse):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

Use third-party utility functions:

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

Where jQuery's $.extend has better performance:

@Nico 2016-05-09 19:56:02

I tested a few and _.extend({}, (obj)) was BY FAR the fastest: 20x faster than JSON.parse and 60% faster than Object.assign, for example. It copies all sub-objects quite well.

@basickarl 2017-04-21 10:02:14

All of your examples are shallow, one level. This is not a good answer. The Question was regarding deep cloning i.e. at least two levels.

@tfmontague 2017-04-21 15:42:01

A deep copy is when an object is copied in its' entirety without the use of reference pointers to other objects. The techniques under the section "Deep copy an array of objects", such as jQuery.extend() and the custom function (which is recursive) copy objects with "at least two levels". So, no not all the examples are "one level" copies.

@josi 2018-02-01 16:53:21

I like your custom copy function, but you should exclude null values, otherwise all null values are being converted to objects, i.e.: out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;

@Hossam Mourad 2018-03-19 10:49:25

@tfmontague The custom function has a bug, it convert any null value to {}. I had to refactor all of my codebase because I was depending heavily on it.

@tfmontague 2018-03-20 15:29:57

@HossamMourad - The bug was fixed by Josi on Feb1 (in the comment above), and I failed to correctly update the answer. Sorry that this bug resulted in a refactor of your code base.

@Steve Griffith 2018-02-26 04:05:16

Looking through this long list of answers nearly all the solutions have been covered except one that I am aware of. This is the list of VANILLA JS ways of deep cloning an object.

  1. JSON.parse(JSON.stringify( obj ) );

  2. Through history.state with pushState or replaceState

  3. Web Notifications API but this has the downside of asking the user for permissions.

  4. Doing your own recursive loop through the object to copy each level.

  5. The answer I didn't see -> Using ServiceWorkers. The messages (objects) passed back and forth between the page and the ServiceWorker script will be deep clones of any object.

@Jack Giffin 2018-04-07 00:24:58

All these have already been converted either in the answers or the comments. I would vote this up if you gave unique code examples for each one though.

@Alireza 2017-04-03 15:37:57

Cloning an Object was always a concern in JS, but it was all about before ES6, I list different ways of copying an object in JavaScript below, imagine you have the Object below and would like to have a deep copy of that:

var obj = {a:1, b:2, c:3, d:4};

There are few ways to copy this object, without changing the origin:

1) ES5+, Using a simple function to do the copy for you:

function deepCopyObj(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }
    throw new Error("Unable to copy obj this object.");
}

2) ES5+, using JSON.parse and JSON.stringify.

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) AngularJs:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

var deepCopyObj = jQuery.extend(true, {}, obj);

5) UnderscoreJs & Loadash:

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

Hope these help...

@Rogelio Triviño 2017-04-03 16:19:25

clone in underscore is not a deep clone in current version

@Alireza 2017-04-04 01:00:44

Thanks. yes as new doc for Underscore... clone_.clone(object) Create a shallow-copied clone of the provided plain object. Any nested objects or arrays will be copied by reference, not duplicated. _.clone({name: 'moe'}); => {name: 'moe'};

@jeff musk 2017-04-14 16:58:45

@Alireza obj = {copy1:'asdf', nest: {copy2: 'asdfa'}} I tried Object.assign({},obj) and find out that it copies property copy1, but does not copy copy2;

@Alireza 2017-04-15 02:21:36

@jeffmusk, the first param in Object.assign, is where you want to start and it's simply could be your first object, so do something like this instead: Object.assign(obj1, obj2);

@kba 2017-05-10 15:52:55

Object.assign does not deep copy. Example: var x = { a: { b: "c" } }; var y = Object.assign({}, x); x.a.b = "d". If this was deep copy, y.a.b would still be c, but it's now d.

@haemse 2017-07-21 10:13:53

Object.assign() only clones the first level of properties!

@pastorello 2017-08-07 16:55:40

what is cloneSO() function?

@mactive 2017-09-12 04:02:04

@pastorello cloneSO is the deepCopyObj. here is a recursive for DEEP clone

@Sophie 2019-03-08 15:21:22

angular.copy is not very performant (see here: github.com/angular/angular.js/issues/11099)

@Константин Ван 2018-01-20 20:26:35

What about asynchronous object cloning done by a Promise?

async function clone(thingy /**/)
{
    if(thingy instanceof Promise)
    {
        throw Error("This function cannot clone Promises.");
    }
    return thingy;
}

@Константин Ван 2019-08-27 16:13:31

Hold on, 5 upvoters, how does it work? I forgot it myself and this looks counterintuitive, now that one and half years has past.

@Sebi 2020-08-22 12:27:49

No idea what it's supposed to do, I'm confused :s

@Константин Ван 2020-08-22 22:41:13

Does Promise.resolve(value) resolve a cloned value? I doubt it, past myself.

@Dima 2010-04-28 11:16:55

// obj target object, vals source object
var setVals = function (obj, vals) {
    if (obj && vals) {
        for (var x in vals) {
            if (vals.hasOwnProperty(x)) {
                if (obj[x] && typeof vals[x] === 'object') {
                    obj[x] = setVals(obj[x], vals[x]);
                } else {
                    obj[x] = vals[x];
                }
            }
        }
    }
    return obj;
};

@opensas 2013-06-22 15:03:59

Lodash has a nice _.cloneDeep(value) method:

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

@TRUMP says to NAZIS - STAND BY 2016-04-07 17:23:49

I advocate deleting this and all other answers which are just one-line references to a utility library's .clone(...) method. Every major library will have them, and the repeated brief non-detailed answers aren't useful to most visitors, who won't be using that particular library.

@Rebs 2017-02-27 00:48:02

An easier way is to use _.merge({}, objA). If only lodash didn't mutate objects in the first place then the clone function wouldn't be necessary.

@Rebs 2017-02-27 00:49:11

Google searches for cloning JS objects refer to here. I'm using Lodash so this answer is relevant to me. Lets not go all "wikipedia deletionist" on answers please.

@Dan Dascalescu 2017-12-31 13:07:15

In Node 9, JSON.parse(JSON.stringify(arrayOfAbout5KFlatObjects)) is a lot faster than _.deepClone(arrayOfAbout5KFlatObjects).

@Mayur Agarwal 2017-10-11 16:02:22

I am late to answer this question, but I have an another way of cloning the object:

   function cloneObject(obj) {
        if (obj === null || typeof(obj) !== 'object')
            return obj;
        var temp = obj.constructor(); // changed
        for (var key in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
                obj['isActiveClone'] = null;
                temp[key] = cloneObject(obj[key]);
                delete obj['isActiveClone'];
            }
        }
        return temp;
    }



var b = cloneObject({"a":1,"b":2});   // calling

which is much better and faster then:

var a = {"a":1,"b":2};
var b = JSON.parse(JSON.stringify(a));  

and

var a = {"a":1,"b":2};

// Deep copy
var newObject = jQuery.extend(true, {}, a);

I have bench-marked the code and you can test the results here:

and sharing the results: enter image description here References: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

@Antoniossss 2018-04-26 08:30:54

its funny but when I run your tests it actually shoed me that method 1 is the slowest one

@SPG 2018-12-05 01:08:58

same as me, block 1 is the lowest!

@Julez 2017-10-15 20:01:27

Here is my way of deep cloning a object with ES2015 default value and spread operator

 const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

const testObj = {
  "type": "object",
  "properties": {
    "userId": {
      "type": "string",
      "chance": "guid"
    },
    "emailAddr": {
      "type": "string",
      "chance": {
        "email": {
          "domain": "fake.com"
        }
      },
      "pattern": "[email protected]"
    }
  },
  "required": [
    "userId",
    "emailAddr"
  ]
}

const makeDeepCopy = (obj, copy = {}) => {
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      makeDeepCopy(obj[item], copy)
    }
    if (obj.hasOwnProperty(item)) {
      copy = {
        ...obj
      }
    }
  }
  return copy
}

console.log(makeDeepCopy(testObj))

@shobhit1 2017-09-09 15:08:58

There are so many ways to achieve this, but if you want to do this without any library, you can use the following:

const cloneObject = (oldObject) => {
  let newObject = oldObject;
  if (oldObject && typeof oldObject === 'object') {
    if(Array.isArray(oldObject)) {
      newObject = [];
    } else if (Object.prototype.toString.call(oldObject) === '[object Date]' && !isNaN(oldObject)) {
      newObject = new Date(oldObject.getTime());
    } else {
      newObject = {};
      for (let i in oldObject) {
        newObject[i] = cloneObject(oldObject[i]);
      }
    }

  }
  return newObject;
}

Let me know what you think.

@JTeam 2017-08-16 06:16:41

As this question is having lot of attention and answers with reference to inbuilt features such as Object.assign or custom code to deep clone, i would like to share some libraries to deep clone,

1. esclone

npm install --savedev esclone https://www.npmjs.com/package/esclone

Example use in ES6:

import esclone from "esclone";

const rockysGrandFather = {
  name: "Rockys grand father",
  father: "Don't know :("
};
const rockysFather = {
  name: "Rockys Father",
  father: rockysGrandFather
};

const rocky = {
  name: "Rocky",
  father: rockysFather
};

const rockyClone = esclone(rocky);

Example use in ES5:

var esclone = require("esclone")
var foo = new String("abcd")
var fooClone = esclone.default(foo)
console.log(fooClone)
console.log(foo === fooClone)

2. deep copy

npm install deep-copy https://www.npmjs.com/package/deep-copy

Example:

var dcopy = require('deep-copy')

// deep copy object 
var copy = dcopy({a: {b: [{c: 5}]}})

// deep copy array 
var copy = dcopy([1, 2, {a: {b: 5}}])

3. clone-deep

$ npm install --save clone-deep https://www.npmjs.com/package/clone-deep

Example:

var cloneDeep = require('clone-deep');

var obj = {a: 'b'};
var arr = [obj];

var copy = cloneDeep(arr);
obj.c = 'd';

console.log(copy);
//=> [{a: 'b'}] 

console.log(arr);

@prograhammer 2017-06-18 06:34:37

I disagree with the answer with the greatest votes here. A Recursive Deep Clone is much faster than the JSON.parse(JSON.stringify(obj)) approach mentioned.

And here's the function for quick reference:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}

@Luis 2017-08-21 22:53:25

I liked this approach but it doesn't handle dates properly; consider adding something like if(o instanceof Date) return new Date(o.valueOf()); after checking for null `

@Harry 2018-03-18 05:19:50

Crashes on circular references.

@WBT 2019-01-14 18:38:35

In latest stable Firefox, this is way longer than the other strategies at that Jsben.ch link, by an order of magnitude or more. It beats the others in the wrong direction.

@Daniel Barde 2017-06-04 20:49:53

Lodash has a function that handles that for you like so.

var foo = {a: 'a', b: {c:'d', e: {f: 'g'}}};

var bar = _.cloneDeep(foo);
// bar = {a: 'a', b: {c:'d', e: {f: 'g'}}} 

Read the docs here.

@tommyalvarez 2017-07-11 17:27:33

I ended up using this, since the JSON.parse(JSON.stringify(obj)) does not keep the original object prototype

@RobbyD 2017-07-20 07:30:29

This is my goto answer. Except that I use Lodash's merge, keeps the syntax somewhat consistent for deep and shallow copying. //Deep copy: _.merge({},foo) //Shallow copy: Object.Assign({}, foo)

Related Questions

Sponsored Content

78 Answered Questions

[SOLVED] What is the JavaScript version of sleep()?

  • 2009-06-04 14:41:10
  • fmsf
  • 2841792 View
  • 2474 Score
  • 78 Answer
  • Tags:   javascript sleep

39 Answered Questions

[SOLVED] Length of a JavaScript object

46 Answered Questions

[SOLVED] How do I remove a property from a JavaScript object?

49 Answered Questions

[SOLVED] Deep cloning objects

  • 2008-09-17 00:06:27
  • NakedBrunch
  • 828842 View
  • 2273 Score
  • 49 Answer
  • Tags:   c# .net clone

57 Answered Questions

[SOLVED] How do I test for an empty JavaScript object?

41 Answered Questions

[SOLVED] How do I loop through or enumerate a JavaScript object?

70 Answered Questions

[SOLVED] How do I correctly clone a JavaScript object?

36 Answered Questions

[SOLVED] What is the !! (not not) operator in JavaScript?

  • 2009-04-24 08:13:58
  • Hexagon Theory
  • 595792 View
  • 3215 Score
  • 36 Answer
  • Tags:   javascript operators

22 Answered Questions

[SOLVED] Checking if a key exists in a JavaScript object?

28 Answered Questions

[SOLVED] What does "use strict" do in JavaScript, and what is the reasoning behind it?

Sponsored Content