5157

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.

5
  • 566
    Eval is not evil. Using eval poorly is. If you are afraid of its side effects you are using it wrong. The side effects you fear are the reasons to use it. Did any one by the way actually answer your question? Commented Mar 22, 2012 at 14:08
  • 15
    Cloning objects is a tricky business, especially with custom objects of arbitrary collections. Which probably why there is no out-of-the box way to do it. Commented Mar 11, 2013 at 22:25
  • 12
    eval() is generally a bad idea because many Javascript engine's optimisers have to turn off when dealing with variables that are set via eval. Just having eval() in your code can lead to worse performance. Commented Sep 8, 2014 at 13:37
  • 12
    Note that JSON method will loose any Javascript types that have no equivalent in JSON. For example: JSON.parse(JSON.stringify({a:null,b:NaN,c:Infinity,d:undefined,e:function(){},f:Number,g:false})) will generate {a: null, b: null, c: null, g: false} Commented May 24, 2017 at 13:06
  • The react community has introduced immutability-helper Commented Jul 6, 2019 at 7:07

67 Answers 67

1 2
3
2

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

Comments

2

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

Comments

1

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);
community wiki

Comments

1

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

Comments

1
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?

Comments

-1

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.

1 Comment

Not a deep clone. Only does one layer of depth. Also doesn't work for arrays or anything with the value null due to incorrect typeof checking.
-5

Cloning an object using today's JavaScript: ECMAScript 2015 (formerly known as ECMAScript 6)

var original = {a: 1};
// Method 1: New object with original assigned.
var copy1 = Object.assign({}, original);
// Method 2: New object with spread operator assignment.
var copy2 = {...original};

Old browsers may not support ECMAScript 2015. A common solution is to use a JavaScript-to-JavaScript compiler like Babel to output an ECMAScript 5 version of your JavaScript code.

As pointed out by @jim-hall, this is only a shallow copy. Properties of properties are copied as a reference: changing one would change the value in the other object/instance.

2 Comments

This doesn't address deep merges. gist.github.com/jimbol/5d5a3e3875c34abcf60a
Wow, this answer is so wrong. Both your methods do a shallow copy of one level. Anyone looking at this answer, move on.
1 2
3

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.