Historical archive
Deep Copy vs. Shallow Copy in JavaScript
The difference between copying references and cloning values, the limits of JSON serialization, and recursive ES5 and ES6 deep-clone implementations.
The essential difference between a deep copy and a shallow copy is whether nested data is independently duplicated or still shared through references.
JavaScript primitive values are copied by value. Objects and arrays are reference values, so a simple assignment copies the reference to the same object.
JSON.parse(JSON.stringify(obj))
Serializing and parsing an object can provide a simple deep copy for JSON-compatible data:
const copy = JSON.parse(JSON.stringify(obj));
It does not work correctly for every JavaScript value:
Dateobjects become strings.RegExpandErrorobjects lose their useful data.- Functions and
undefinedproperties are omitted. NaN,Infinity, and-Infinitybecomenull.- Circular references cause serialization to fail.
ES5 recursive clone
function deepClone(origin, target) {
var result = target || {};
var toString = Object.prototype.toString;
var arrayType = '[object Array]';
for (var key in origin) {
if (Object.prototype.hasOwnProperty.call(origin, key)) {
if (typeof origin[key] === 'object' && origin[key] !== null) {
result[key] = toString.call(origin[key]) === arrayType ? [] : {};
deepClone(origin[key], result[key]);
} else {
result[key] = origin[key];
}
}
}
return result;
}
ES6 clone with WeakMap
A WeakMap remembers previously cloned objects and prevents infinite recursion when the input contains cycles.
function deepClone(origin, seen = new WeakMap()) {
if (origin === undefined || origin === null || typeof origin !== 'object') {
return origin;
}
if (origin instanceof Date) {
return new Date(origin);
}
if (origin instanceof RegExp) {
return new RegExp(origin);
}
const existing = seen.get(origin);
if (existing) {
return existing;
}
const target = new origin.constructor();
seen.set(origin, target);
for (const key in origin) {
if (Object.prototype.hasOwnProperty.call(origin, key)) {
target[key] = deepClone(origin[key], seen);
}
}
return target;
}
Modern runtimes also provide structuredClone() for many common structured data types, although it cannot clone every possible JavaScript value.