HuntExams Academy logo
JavaScriptIntermediate#objects

How do you deep clone an object?

Answer

Use structuredClone for most data, or a recursive clone for custom needs. Spread and Object.assign only copy one level, and JSON round-tripping loses Dates, Maps, functions and undefined.

Example

const deep = structuredClone(obj);
const shallow = { ...obj }; // nested objects still shared

Detailed explanation

A deep clone creates a separate object graph: nested objects in the copy are independent of those in the original. This matters when modifying application state, preparing test fixtures, or transforming data without changing its source. By contrast, object spread and Object.assign() create shallow copies: the outer object is new, but nested references remain shared. For example, after const copy = { ...obj }, changing copy.address.city also changes obj.address.city if address is an object. A good interview answer should explain this reference behaviour before listing cloning techniques.

For most supported data, use const deep = structuredClone(obj). Available in modern browsers and Node.js, it handles nested objects, arrays, Date, Map, Set, typed arrays, and circular references. Its structured clone algorithm tracks previously visited references, so cycles do not cause infinite recursion and repeated references remain shared within the cloned graph. However, it is not a universal object copier: functions, DOM nodes, and WeakMap cannot be cloned and generally cause a DataCloneError. It also does not preserve custom class prototypes, property descriptors, or accessor definitions, so do not expect cloned class instances to retain their methods.

JSON.parse(JSON.stringify(obj)) is acceptable only for deliberately JSON-compatible data. Dates become strings; Map and Set typically become empty objects; undefined and function-valued object properties disappear. In arrays, those unsupported values become null. Circular references and BigInt values throw errors, while NaN and Infinity become null. Therefore, JSON round-tripping is serialization followed by parsing, not a general-purpose deep-cloning algorithm. Use it only when these conversions match your requirements.

For custom needs, write a recursive clone or use a well-tested library, explicitly defining which types and semantics you support. A basic recursive implementation handles primitives, arrays, and plain objects, but a robust version needs a WeakMap mapping source objects to their clones to handle cycles and preserve repeated references. Register each clone before traversing its children. Decide how to handle prototypes, symbols, descriptors, and specialised types. Interviewers usually judge whether you understand independence, supported types, reference relationships, and limitations—not whether you can produce a short recursive function that silently corrupts data.

Key points to remember

  • Spread and Object.assign() copy only the outer level; nested objects remain shared.
  • Prefer structuredClone(obj) for supported data, including circular structures, Dates, Maps, and Sets.
  • structuredClone() cannot clone functions and does not preserve custom class prototypes.
  • JSON round-tripping changes or drops unsupported values and fails on circular references.
  • Custom recursive cloning needs explicit type handling and reference tracking, commonly with a WeakMap.

Common mistakes candidates make

  • Calling { ...obj } a deep clone without checking nested reference equality.
  • Using JSON.parse(JSON.stringify(obj)) without considering data loss or conversion.
  • Writing recursion without cycle detection or assuming every object is a plain object.

Likely follow-up questions

How can you verify that nested objects were cloned?

For an object with a nested address, check that copy !== original and copy.address !== original.address. Then modify copy.address.city and confirm that the original value stays unchanged.

Why does a recursive clone need a WeakMap?

It records the clone associated with each source object so repeated visits return the existing clone. This prevents infinite recursion for cycles and preserves aliasing when multiple properties reference the same object.

Should you deep clone the entire state object for every update?

Usually not: deep cloning can be expensive and replaces references even for unchanged data. For immutable updates, copy only the objects along the changed path and share unchanged branches.

Interview tip: Start with shallow versus deep reference behaviour, recommend structuredClone(), and then explain the limitations that justify a custom approach.

Related Interview Questions

1
JavaScriptIntermediate#es6#operators

What is optional chaining and nullish coalescing?

Open
2
JavaScriptBeginner#fundamentals

Difference between null and undefined?

Open
3
JavaScriptIntermediate#es6#collections

Difference between Map/Set and plain objects/arrays?

Open