Mastering Deep Copy in JavaScript: Why It Matters and How to Implement It
This article explains what deep copy is, why it is essential for avoiding side‑effects in mutable data structures, outlines its practical benefits such as safe snapshots and independent cloning of complex objects, and provides a complete JavaScript implementation that handles primitives, circular references, and special built‑in types.
What Is Deep Copy?
Deep copy (or deep cloning) creates a new object that replicates not only the top‑level values of the source but also recursively copies every nested reference, ensuring that the original and the clone share no mutable state.
Why Deep Copy Matters
Avoids hidden bugs caused by shared mutable data, especially in concurrent, asynchronous, or modular code.
Enables safe snapshots, undo/redo mechanisms, and reliable serialization/persistence.
Allows independent duplication of complex structures such as trees, graphs, or nested arrays/dictionaries for use in different contexts.
Implementation Principle
The core idea is the same across languages: allocate new memory for the clone and recursively traverse the object graph, copying each property while handling special cases and circular references.
JavaScript Deep Copy Function
The following implementation demonstrates a robust deep‑copy routine that works for primitives, arrays, plain objects, Date, RegExp, Map, Set, and correctly resolves circular references using a WeakMap to track visited objects.
function deepCopy(obj, visited = new WeakMap()) {
// Primitive values and null are returned directly
if (obj === null || typeof obj !== 'object') return obj;
// Circular reference: return the previously created copy
if (visited.has(obj)) return visited.get(obj);
// Special built‑in objects
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
if (obj instanceof Map) {
const copy = new Map();
visited.set(obj, copy);
obj.forEach((value, key) => copy.set(key, deepCopy(value, visited)));
return copy;
}
if (obj instanceof Set) {
const copy = new Set();
visited.set(obj, copy);
obj.forEach(value => copy.add(deepCopy(value, visited)));
return copy;
}
// Arrays and plain objects
const copy = Array.isArray(obj) ? [] : {};
visited.set(obj, copy);
// Copy all own property keys, including symbols
Reflect.ownKeys(obj).forEach(key => {
copy[key] = deepCopy(obj[key], visited);
});
return copy;
}Starting from the source object, the algorithm visits each field: primitive values are copied directly, while reference types trigger the creation of a new container and a recursive copy of their internal fields. This process continues until the deepest level consists only of immutable primitives, resulting in a completely independent object tree.
Architect Chen
Sharing over a decade of architecture experience from Baidu, Alibaba, and Tencent.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
