Deep cloning objects in JavaScript
JavaScript developers are re-evaluating how to “deep clone” complex objects now that the browser-native `structuredClone` API is widely available. Many welcome it as a safer, more complete alternative to long‑standing hacks like `JSON.parse(JSON.stringify())` and heavy utilities like Lodash, but note performance trade-offs and limitations around functions, classes, and prototypes. A recurring theme is whether deep cloning is a legitimate tool (for undo/redo, worker communication, immutable state, etc.) or a code smell that signals deeper design issues in how state and data structures are modeled.
structuredClone behavior and limitations
- Uses the web “structured clone” algorithm originally designed for cross-realm data transfer.
- Does not preserve prototype chains or class instances; user-defined classes lose their type and become plain data.
- Cannot clone functions or objects with arrow functions; this is by design due to closures and hidden bindings.
- Supports many built-in types (Date, Map, Set, SharedArrayBuffer, etc.), unlike the JSON hack.
- Throws on unsupported values (e.g., functions), which some see as safer than silent degradation.
Performance debates
- Some report
structuredClonebeing significantly slower thanJSON.parse(JSON.stringify(...))for simple objects in tight loops (e.g., ~6x slower). - Others point out that JSON-based cloning mangles non-JSON types, so raw speed is not the only criterion.
- A proprietary custom deep copy implementation and small recursive functions are claimed to outperform both, but details are sparse.
- lodash
cloneDeepis noted as surprisingly heavy (~17 KB minified) and pulls in many helper utilities.
Do you really need deep cloning?
- Several argue that needing deep clones is often a design smell, especially in app code and UIs.
- Preferred approaches: immutability patterns, shallow copies plus careful mutation, or redesigning APIs to avoid shared mutable state.
- Others counter that deep cloning is legitimate in various scenarios.
Common use cases cited
- Undo/redo stacks and time-travel of state (e.g., editors, games, geographic data).
- Passing data into untrusted or mutating libraries while preserving original input.
- Logging: devtools show live object views, so cloning or stringifying captures a snapshot.
- Game engines / simulations (e.g., Monte Carlo search) that require copying entire game state many times.
- Component frameworks (React/Vue) where immutable updates or defensive copying simplify reasoning.
JSON.stringify vs structuredClone
- JSON-based cloning is fast and simple but:
- Drops functions and
undefined; mishandles Sets/Maps; auto-stringifies Dates; fails on circular references. - Can silently “corrupt” data by omitting or altering non-JSON types.
- Drops functions and
structuredCloneis seen as a more principled, explicit alternative with clear error behavior.
Naming, proposals, and alternatives
- Some dislike the name “structuredClone,” preferring “deepClone”; others say “structured” is a useful warning that it’s not a perfect clone.
- Deep cloning is contrasted with future immutable Record/Tuple proposals and with libraries like Immer/Mutative/Limu for ergonomic immutable updates.