When you want a complete copy of an object (i.e. the object properties and the values inside those properties, etc...), that is called deep cloning.
If an object can be serialized to JSON, then you can create a deep clone of it with a combination of JSON.parse
and JSON.stringify
:
var existing = { a: 1, b: { c: 2 } };
var copy = JSON.parse(JSON.stringify(existing));
existing.b.c = 3; // copy.b.c will not change
Note that JSON.stringify
will convert Date
objects to ISO-format string representations, but JSON.parse
will not convert the string back into a Date
.
There is no built-in function in JavaScript for creating deep clones, and it is not possible in general to create deep clones for every object for many reasons. For example,
Assuming that you have a "nice" object whose properties only contain primitive values, dates, arrays, or other "nice" objects, then the following function can be used for making deep clones. It is a recursive function that can detect objects with a cyclic structure and will throw an error in such cases.
function deepClone(obj) {
function clone(obj, traversedObjects) {
var copy;
// primitive types
if(obj === null || typeof obj !== "object") {
return obj;
}
// detect cycles
for(var i = 0; i < traversedObjects.length; i++) {
if(traversedObjects[i] === obj) {
throw new Error("Cannot clone circular object.");
}
}
// dates
if(obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// arrays
if(obj instanceof Array) {
copy = [];
for(var i = 0; i < obj.length; i++) {
copy.push(clone(obj[i], traversedObjects.concat(obj)));
}
return copy;
}
// simple objects
if(obj instanceof Object) {
copy = {};
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
copy[key] = clone(obj[key], traversedObjects.concat(obj));
}
}
return copy;
}
throw new Error("Not a cloneable object.");
}
return clone(obj, []);
}