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

@Akash 2019-03-16 06:07:30

Keep It Super Simple (KISS):

If there is an object, it should (ideally) have a constructor. If you don't have a constructor for an object; I feel, you should create a constructor first.

OK, now cloning objects:

function SampleObjectConstructor(config) {
    this.greet = config.greet;
}
// custom-object's prototype method
SampleObjectConstructor.prototype.showGreeting = function(){
  alert(this.greet);
}

var originalObject = new SampleObjectConstructor({greet: 'Hi!'});
var clonedObj = new SampleObjectConstructor(originalObject);

console.log(originalObject); // SampleObjectConstructor {greet: "Hi!"}
console.log('clonedObj : ', clonedObj) // SampleObjectConstructor {greet: "Hi!"}
console.log('cloned successfully?', originalObject !== clonedObj); // cloned successfully? true

CASE II : If the object being cloned is not a custom object with its prototype methods; the inbuilt object constructor - Object can work just as well i.e. new Object(originalObject) will clone the original object for you. In such a case, you don't even need to write your own constructor.

var originalObject = {
    foo: 'bar'
}

var clonedObject = new Object(originalObject);

console.log(originalObject); // {foo: "bar"}
console.log(clonedObject); // {foo: "bar"}
console.log(originalObject !== clonedObject); // false

Good Luck...

@Sumer 2019-03-13 12:50:40

Lean and Clean ES6 code;

function cloneObj(obj, newObj = {}) {
   if (obj === null || typeof obj !== 'object') return obj;

   if (obj instanceof Date) return new Date(obj.getTime());
   if (Array.isArray(obj)) return [...obj];
   if (obj instanceof Object) {
       for (let [key, value] of Object.entries(obj)) {
           newObj[key] = (typeof value === 'object') ? cloneObj(value) : value;
       }
   }
}

@Suraj Rao 2019-03-13 13:46:25

if (Array.isArray(obj)) return [...obj]; will not work as you intend in case of array with objects nested

@Eternal Darkness 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?

@Jeremy Banks 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();

@Jeremy Banks 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.

@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;
}

@TinhNQ 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.)

Reference medium.com

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

@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 })

@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.

@Roymunson 2018-08-15 20:26:11

Can you explain what is happening in this code?

@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.

@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 fastest way to deep clone an object (it beats out 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 this 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.

@rahpuser 2014-11-25 21:37:12

@trysis Object.create is not cloning the object, is using the prototype object... jsfiddle.net/rahpuser/yufzc1jt/2

@Jeremy Anderson 2015-01-10 01:23:04

I was scoping this npm module when I found this question. Great answer. I wonder if there's any feedback on that module, though? I glanced at the source and it seems alright. I especially like this quote: "copies the ES5 descriptor of every property that Object.getOwnPropertyDescriptor() returns".

@Karlen Kishmiryan 2015-05-29 09:52:16

This method will also remove the keys from your object, which have functions as their values, because the JSON doesn't support functions.

@dnlgmzddr 2015-07-30 21:37:10

Also keep in mind that using JSON.parse(JSON.stringify(obj)) on Date Objects will also convert the date back to UTC in the string representation in the ISO8601 format.

@datacarl 2015-09-30 19:45:55

JSON.stringify doesnt convert String or Function since they are not valid JSON. So {type: String, value: 123} would become {"value": 123} which is probably not what you want.

@Josh Mc 2015-11-28 23:09:01

@rich remer 2016-02-13 05:25:15

JSON approach also chokes on circular references.

@inferus-vv 2016-05-04 09:11:50

If you have functions as values of your object - it will NOT work for you.

@Dheeraj Bhaskar 2016-07-12 11:31:20

JSON approach will fail to copy anything that is not part of the JSON spec (json.org) including date objects, functions, circular references among others

@D. Hayes 2016-10-12 20:23:06

Just came by to add comment that this throws away values that are Symbol objects as well.

@tom10271 2016-10-17 07:45:08

Will JSON clone method faster than Object.assign({}, objToClone)?

@velop 2016-10-23 21:40:15

@aokaddaoc no Object.assign is much faster. I added it to the benchmark given in the answer.

@Íhor Mé 2016-11-02 16:22:44

Copying larger objects gets slightly different benchmarks than this.

@Íhor Mé 2016-11-02 18:00:45

Also, in lodash version of the benchmark cloneDeep would be correct. clone(a,true) is an inadequate comparison, as it only copies up to 2 depth levels.

@Íhor Mé 2016-11-02 18:43:27

Mind that Set doesn't get parsed by JSON.stringify

@Garrett Simpson 2016-11-03 18:00:14

@velop , Object.assign({}, objToClone) seems like it does a shallow clone though -- using it while playing around in the dev tools console, the object clone still pointed to a reference of the cloned object. So I don't think it's really applicable here.

@RobertoNovelo 2016-11-07 22:35:54

In my experience, this also replaces special chars with their UTF8 representation.

@Rico Kahler 2016-12-18 00:17:42

@Legends 2017-01-09 09:23:56

Only properties are cloned not functions, just to mention: for example: {a:function(){alert("hi");}, b: "I am b"} --> here only property b is cloned.

@Tarun 2017-01-31 12:35:54

What if obj has a circular JSON structure?

@Florian Loch 2017-03-06 17:05:44

Results completely changed with your benchmark, at least for me running a decent version of Chrome. Perhaps the answer should get updated regarding this?

@Florian Loch 2017-03-07 11:06:28

Also MDN states that Object.assign() CANNOT be used for deep cloning.

@prograhammer 2017-06-18 06:36:03

A recursive deep clone is much faster than the JSON.parse/JSON.stringify approach. See my answer here: stackoverflow.com/a/44612374/1110941

@Jenny O'Reilly 2017-11-12 16:38:06

This also removes the exact type of the object, right? So that instanceof checks no longer work on the resulting object. So this is rather a "primitive" copying than a real deep cloning.

@Andy 2017-12-04 23:31:48

it's no longer the fastest in Chrome

@loctrice 2018-02-26 16:24:34

It's also worth noting that properties with undefined values will not be included if you use stringify. This problem is what drove me to this thread, so I can't use stringify.

@Jason Goemaat 2018-07-26 04:26:38

@AlexanderF. o1 = {a:1, b:{c:2,d:[1,2,3,{e:555}]}, f: function(){console.log('Hi!')}}; o2 = Object.assign({}, o1); o2.b.c = "It was shallow..."; console.log(o1.b.c);

@Alexander F. 2018-07-26 16:39:38

@JasonGoemaat you're absolutely right! I remember playing with it a few weeks down the road and finding unexpected results. Forgot about my silly comment here though. Cannot edit anymore so will just delete it.

@Cemre 2018-08-02 22:17:07

“This one line of Javascript made FT.com 10 times slower” @adgad medium.com/ft-product-technology/…

@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

@Gurebu Bokofu 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?

@Gurebu Bokofu 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

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

Note: This is a reply to another answer, not a proper response to this question. If you wish to have fast object cloning please follow Corban's advice in their answer to this question.


I want to note that the .clone() method in jQuery only clones DOM elements. In order to clone JavaScript objects, you would do:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

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

More information can be found in the jQuery documentation.

I also want to note that the deep copy is actually much smarter than what is shown above – it's able to avoid many traps (trying to deep extend a DOM element, for example). It's used frequently in jQuery core and in plugins to great effect.

@S. Kirby 2012-09-02 20:11:31

For those who didn't realize, John Resig's answer was probably intended as a kind of response/clarification to ConroyP's answer, instead of a direct reply to the question.

@Rune FS 2013-03-27 08:16:19

@ThiefMaster github.com/jquery/jquery/blob/master/src/core.js at line 276 (there's a bit of code that does something else but the code for "how to do this in JS" is there :)

@Alex W 2013-04-11 14:24:13

Here's the JS code behind the jQuery deep copy, for anyone interested: github.com/jquery/jquery/blob/master/src/core.js#L265-327

@Jon Jaques 2014-01-09 22:40:49

Since there seems to be some contention around using jQuery, thought I would mention that I've extracted the extend functionality out to a standalone script: gist.github.com/jonjaques/3036701

@John Resig 2014-01-21 03:37:38

Woah! Just to be super-clear: no idea why this response was picked as the right answer, this was a reply to responses given below: stackoverflow.com/a/122190/6524 (which was recommending .clone(), which is not the right code to be using in this context). Unfortunately this question has gone through so many revisions the original discussion is no longer even apparent! Please just follow Corban's advice and write a loop or copy the properties directly over to a new object, if you care about speed. Or test it out for yourself!

@albanx 2014-02-28 17:29:51

If my objects has a reference to a dom element (let say obj.div = document.getElementById('id') ), does this also clone the dom element and puts it on the document?

@Octopus 2014-05-14 04:56:29

A non-jQuery equivalent of this would be var newobj = eval(oldobj.toSource()).

@RobG 2014-08-15 23:48:43

@albanx—the short answer is no. If you have a question, ask it as a question. Posting it as a comment to an old question that is now irrelevant is unlikely to be helpful. To clone a DOM element use its cloneNode method. To put it in the document, use insertBefore or appendChild or one of the other insertion or replacement methods.

@albanx 2014-08-17 07:40:40

@RobG I work with javascript complex object with reference to dom, and a clone of them will clone only the reference and not the dom element obviously. I know very well the cloneNode and company jquery functions and the comment it is not irrelevant, is just a completion to the question.

@Camilo Martin 2014-09-22 00:21:47

@albanx No, you were asking a question in the comments of an answer, which is already frowned upon, and it wasn't any sort of "completion to the question", you were just drawing attention to your own off-topic problem, which gladly for you was met with condescendence from RobG, which you even reply in a pedantic manner ("I know very well the cloneNode and company"), despite being clear by your question (and response) that you are at a novice level with javascript.

@albanx 2014-09-22 14:00:13

@CamiloMartin No camilo, my question is just a point of clarification, what does that clone ( it does not clone referenced objects). Should be clear that this clone only primitive properties of an object. so you and robg think that I should open a new question like "does the reply of this question also satisfy my question?".

@Camilo Martin 2014-09-23 01:32:39

@albanx You asked if .clone() will insert new objects in the DOM. That's a totally off-topic new question and yes, you should open a new question since this isn't a forum but a Q&A site. (Not that I encourage hijacking forum threads either.)

@mrshickadance 2015-01-14 14:25:09

What about a library like lodash with the clone tool? lodash.com/docs#clone

@gphilip 2015-01-22 08:30:39

This is a JavaScript question (no mention of jQuery).

@Awesomeness01 2015-04-30 02:22:57

How would one do this without using jQuery?

@bearoff 2015-06-24 13:27:22

According to the documentation for extend(), deep copy makes sense only for real merges of objects, and has no sense when using extend() to just clone an object.

@hehe 2015-08-19 07:38:38

This is the very good method, but I have a problem with this because it does NOT convert array properly. it changed array into objects with property names 0,1,2... Therefore I end up using JSON.parse(JSON.stringify(data)) which worked perfectly for me

@lepe 2015-10-20 04:02:31

Be aware that this method will not preserve setters and getters

@satJ 2015-10-27 16:31:05

This won't work if the object has cyclic properties. For such cases, if you want to deep copy, use either angular.copy or lodash's _.cloneDeep

@nf071590 2015-12-22 00:36:51

Answer is useful if using jQuery and I'm lazy; I'm lazy only. Therefore this answer is not useful. +1 @Corban Brook's answer below.

@Brandon K 2016-03-01 14:41:26

With ES6 you can invoke the spread operator: let person = { firstname: "foo", lastname: "bar", address: { city: "Baz"} }; let clonePerson={...person }; delete clonePerson.firstname; console.log(clonePerson.firstname);//undefined console.log(person.firstname);//"foo" This only works at the first level deep: delete clonePerson.address.city; console.log(clonePerson.address.city);//undefined console.log(person.address.city);//undefined You'd have to recursively use the spread operator... spread

@RobG 2016-05-23 06:46:46

@superluminary—so you thought it was worth a down vote based on the content, but didn't because of the author? This isn't even an answer to the OP, how can it not cop a down vote?

@Twifty 2016-10-09 16:57:03

The question states javascript in both the title and body. It mentions nothing of jQuery. So, why is a jQuery answer so highly voted?

@Manoj Yadav 2017-04-12 12:48:00

without jquery Object.create method can be used to clone a object. var newObject = Object.create(oldObject);

@Yuvaraj 2017-04-24 04:53:53

Hey Guys ... How about es6 Object.assign() ?

@HoldOffHunger 2017-08-15 13:46:07

@John Resig: That approach fails when your Object contains any type of data that is more complicated than a scalar.

@faintsignal 2017-09-06 19:10:08

Given the question the accepted answer ought to be one that uses vanilla JS in my opinion.

@1owk3y 2017-11-30 23:05:41

Attempted to use Object.assign() - it does not even pretend to work as expected - this solution worked a treat!

@John 2017-12-30 00:27:36

Down-voted for answering a JavaScript question with a jQuery answer. Down-voted the OP too for cheaping out. Frameworks and libraries are not written well and dump tons of bandwidth on clients. Do it right the first time: professionals use real code.

@metaColin 2018-01-18 19:44:31

Since it only offers a jQuery solution, this answer should not be marked as the accepted correct answer. It's just causing a confusing feedback loop.

@Jack Giffin 2018-04-07 00:20:49

I took a wee bitty peep at the source code (code.jquery.com/jquery-3.3.1.js)... disgusting. Simply vomit-inducing wretched garbage. Do not use jQuery. Ever.

@Emobe 2019-03-13 13:35:56

what a mess. this is supposedly a reply to another answer, obviously should be a comment and not an answer. Secondly, op never mentioned jQuery so you were "replying" to an invalid answer.

@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.

@tfmontague 2016-05-17 13:36:31

@NicoDurand - Are your performance tests online?

@Karl Morrison 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 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;
}

@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

@Jeremy Banks 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))

@Zen 2017-11-10 08:21:22

That's not deep clone, and you're doing it wrong.

@Julez 2018-05-29 07:15:06

please explain yourself instead of saying you're doing it wrong...

@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)

@Redu 2017-04-05 15:06:39

Without touching the prototypical inheritance you may deep lone objects and arrays as follows;

function objectClone(o){
  var ot = Array.isArray(o);
  return o !== null && typeof o === "object" ? Object.keys(o)
                                                     .reduce((r,k) => o[k] !== null && typeof o[k] === "object" ? (r[k] = objectClone(o[k]),r)
                                                                                                                : (r[k] = o[k],r), ot ? [] : {})
                                             : o;
}
var obj = {a: 1, b: {c: 2, d: {e: 3, f: {g: 4, h: null}}}},
    arr = [1,2,[3,4,[5,6,[7]]]],
    nil = null,
  clobj = objectClone(obj),
  clarr = objectClone(arr),
  clnil = objectClone(nil);
console.log(clobj, obj === clobj);
console.log(clarr, arr === clarr);
console.log(clnil, nil === clnil);
clarr[2][2][2] = "seven";
console.log(arr, clarr);

@Matt Browne 2012-11-11 17:53:39

Here's a version of ConroyP's answer above that works even if the constructor has required parameters:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

This function is also available in my simpleoo library.

Edit:

Here's a more robust version (thanks to Justin McCandless this now supports cyclic references as well):

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Related Questions

Sponsored Content

60 Answered Questions

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

37 Answered Questions

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

35 Answered Questions

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

  • 2009-04-24 08:13:58
  • Hexagon Theory
  • 448975 View
  • 2636 Score
  • 35 Answer
  • Tags:   javascript operators

45 Answered Questions

71 Answered Questions

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

  • 2009-06-04 14:41:10
  • fmsf
  • 2095962 View
  • 1790 Score
  • 71 Answer
  • Tags:   javascript sleep

20 Answered Questions

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

36 Answered Questions

[SOLVED] Length of a JavaScript object

26 Answered Questions

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

41 Answered Questions

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

  • 2009-03-25 01:39:45
  • falmp
  • 1581059 View
  • 2210 Score
  • 41 Answer
  • Tags:   javascript json

41 Answered Questions

[SOLVED] Deep cloning objects

  • 2008-09-17 00:06:27
  • NakedBrunch
  • 727731 View
  • 1993 Score
  • 41 Answer
  • Tags:   c# .net clone

Sponsored Content