If your object is "small" and contains exclusively serializable properties, a simple deepCopy hack using JSON serialization should be OK. But, if your object is large, you could run into problems. And if it contains unserializable properties, those'll go missing:
var o = {
a: 1,
b: 2,
sum: function() { return a + b; }
};
var o2 = JSON.parse(JSON.stringify(o));
console.log(o2);
Yields:
Object {a: 1, b: 2}
Interestingly enough, a fair number of deep-copy solutions in C# are similar serialization/deserialization tricks.
Addendum: Not sure what you're hoping for in terms of comparing the objects after the copy. But, for complex objects, you generally need to write your own Compare() and/or Equals() method for an accurate comparison.
Also notable, this sort of copy doesn't preserve type information.
JSON.parse(JSON.stringify(new A())) instanceof A === false
Answer from svidgen on Stack OverflowIf your object is "small" and contains exclusively serializable properties, a simple deepCopy hack using JSON serialization should be OK. But, if your object is large, you could run into problems. And if it contains unserializable properties, those'll go missing:
var o = {
a: 1,
b: 2,
sum: function() { return a + b; }
};
var o2 = JSON.parse(JSON.stringify(o));
console.log(o2);
Yields:
Object {a: 1, b: 2}
Interestingly enough, a fair number of deep-copy solutions in C# are similar serialization/deserialization tricks.
Addendum: Not sure what you're hoping for in terms of comparing the objects after the copy. But, for complex objects, you generally need to write your own Compare() and/or Equals() method for an accurate comparison.
Also notable, this sort of copy doesn't preserve type information.
JSON.parse(JSON.stringify(new A())) instanceof A === false
You can do it that way, but it's problematic for some of the reasons listed above:
I question the performance.
Do you have any non-serializable properties?
And the biggest: your clone is missing type information. Depending upon what you're doing, that could be significant. Did the implementor add methods to the prototype of your original objects? Those are gone. I'm not sure what else you'll lose.
Javascript deep copy using JSON.parse and JSON.stringify - Stack Overflow
What is the most efficient way to deep clone an object in JavaScript? - Stack Overflow
What are the dangers of Deep-copying objects using JSON.parse(JSON.stringify(obj))?
[Performance] Deep Copy vs JSON Stringify / JSON Parse
As metioned in other answer JSON methods to deep copy is unreliable with non primitive data types. In modern JS we can find new method called structuredClone() for deep copy.
var obj = {name: {firstName: 'John', lastName: 'Doe'}, age: 25 };
So to create copy of obj into obj1, We can do something like
var obj1 = structuredClone(obj);
In short, this is a simple but unreliable deep copy that works for simple JavaScript objects. But it would likely fail for some non-primitive data types' properties.
const set = new Set();
set.add(1);
set.add(2);
const map = new Map();
map.set('Jessie', {phone: "213-555-1234", address: "123 N 1st Ave"})
const obj = {
foo: () => 'bar',
date: new Date(),
undefined,
set,
map,
}
console.log(obj);
let unreliableNewObj = JSON.parse(JSON.stringify(obj));
console.log(unreliableNewObj); // some properties are lost, some properties are changed like set and map, can compare the result
// ES6 shallow copy that may help
let reliableNewObj = {
...obj,
}
console.log(reliableNewObj);
// 'real' deep copy from library
// https://lodash.com/docs#cloneDeep
let deepObj = _.cloneDeep(obj); // if _ is imported
console.log(deepObj)
For a reliable deep copy, alternatives are:
- libraries like lodash
- implement by ourselves, like this post, maybe quite complicated though.
Native deep cloning
There's now a structuredClone(value) function supported in all major browsers and node >= 17. It has polyfills for older systems.
structuredClone(value)
If needed, loading the polyfill first:
import structuredClone from '@ungap/structured-clone';
See this answer for more details, but note these limitations:
- Function objects cannot be duplicated by the structured clone algorithm; attempting to throws a DataCloneError exception.
- Cloning DOM nodes likewise throws a DataCloneError exception.
- Certain object properties are not preserved:
- The lastIndex property of RegExp objects is not preserved.
- Property descriptors, setters, getters, and similar metadata-like features are not duplicated. For example, if an object is marked readonly with a property descriptor, it will be read/write in the duplicate, since that's the default.
- The prototype chain is not walked or duplicated.
Older answers
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()
Run code snippetEdit code snippet Hide Results Copy to answer Expand
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,
- lodash -
cloneDeep; can be imported separately via the lodash.clonedeep module and is probably your best choice if you're not already using a library that provides a deep cloning function - Ramda -
clone - AngularJS -
angular.copy - jQuery -
jQuery.extend(true, { }, oldObject);.clone()only clones DOM elements - just library -
just-clone; Part of a library of zero-dependency npm modules that do just do one thing. Guilt-free utilities for every occasion.
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);
The biggest problem with using this method to deep-copy an object is the fact the object must be JSON serializable. For example, the following object:
let obj = {
func: function() {
console.log("hello world!");
}
}
Would not be copied properly since functions are not JSON serializable. There are many other issues as well, such as with cyclic references. This really only works for simple, plain objects and thus isn't a particularly good solution. I would recommend checking out something like an underscore or a lodash for high-performance deep copying.
A few problems exist with the JSON.parse(JSON.stringify(obj))
The main issue for most developers is the loss of anything not part of the JSON spec
- Any internal getters and setters will be lost.
- Destruction of date objects (Dates will be converted to strings
- Class prototypes will be lost.
The JSON method will also throw an exception when parsing circular references.
That said it does have some advantages for it:
- Raw speed the JSON method wins out over even most shallow copy methods in benchmarks
- Due to native implementation in the browser unlike a library it does not need to be shipped to the client, possibly also speeding up page load times.
As far as creating a truly deep copy of the object... it will be a truly deep copy as it will go as many levels into the object as it can, it won't be in that it will discard certain information, as outlined above.