Glossary / Deep copy
Deep copy
A deep copy recursively duplicates nested data so mutations to the copied graph do not affect the original graph, within the copy operation’s defined type support. There is no universal deep-copy behavior: functions, prototypes, accessors, Symbols, cycles, shared references, DOM nodes, file handles, and application resources all require explicit policy.
Structured cloning and lossy shortcuts
const original = { date: new Date(), nested: { value: 1 } };
const copy = structuredClone(original);
copy !== original; // true
copy.nested !== original.nested; // true
structuredClone supports many built-in types and cyclic references. It does not clone functions and does not generally preserve arbitrary class prototypes or property descriptors. Some transferable types can be moved rather than copied using transfer options, detaching the source. JSON stringify/parse is not a general deep clone: it fails on cycles/BigInt and loses several values/types.
A handwritten recursive clone must track visited objects to handle cycles and should preserve repeated references intentionally if graph identity matters. It must decide how to handle getters (invoke or copy descriptor), Maps/Sets, typed arrays, errors, and host objects. Deep cloning can be expensive in CPU and memory; immutable updates, explicit DTOs, or ownership transfer are often clearer.
Interview questions
- Why is deep copy not one universal operation? Object graphs contain types and identity semantics requiring policy choices.
- Does structuredClone support cycles? Yes, for supported values.
- Does it preserve arbitrary class prototypes? Generally no.
- Why is JSON round-tripping a poor clone? It is lossy and fails for cycles and unsupported values.