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 structuredClone being significantly slower than JSON.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 cloneDeep is 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.
  • structuredClone is 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.