Deep Clone Complex Objects (Dates, Functions, Circular References)

Implement a robust deep-clone that handles Dates, RegExps, functions (optionally), and circular references — and know tradeoffs.

advancedBrowser and domjavascriptdeep cloneobjectscircular references
Published: 11/12/2025
Updated: 11/12/2025

Advertisement

Question

Create a deepClone(obj) that:

  • Copies Dates and RegExps correctly
  • Preserves nested arrays and objects
  • Handles circular references
  • Optionally clones functions (document the tradeoffs)

Answer

JSON.parse(JSON.stringify(...)) is a common quick hack but it strips Dates to strings, loses undefined, functions, and fails on circular references. A robust solution must:

  • Detect object types (Date, RegExp, Map, Set, Array, Object)
  • Track visited objects to handle circular references
  • Optionally clone functions (usually by reference; cloning function source is risky)

Tradeoffs & Performance:

  • Deep cloning is expensive — avoid unless necessary
  • For large structures, prefer structural sharing (immutable patterns) or selective cloning
  • For complex objects (Buffer, TypedArray), support for transferable objects may be needed

Implementation (safe clone with circular refs)

function deepClone(obj, map = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj;

  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (obj instanceof Map) {
    const res = new Map();
    obj.forEach((v, k) => res.set(deepClone(k, map), deepClone(v, map)));
    return res;
  }
  if (obj instanceof Set) {
    const res = new Set();
    obj.forEach((v) => res.add(deepClone(v, map)));
    return res;
  }
  if (map.has(obj)) return map.get(obj); // circular reference

  const copy = Array.isArray(obj) ? [] : {};
  map.set(obj, copy);

  Reflect.ownKeys(obj).forEach((key) => {
    const desc = Object.getOwnPropertyDescriptor(obj, key);
    if (desc.get || desc.set) {
      Object.defineProperty(copy, key, desc); // preserve accessors
    } else {
      copy[key] = deepClone(obj[key], map);
    }
  });

  return copy;
}

Notes:

  • Functions are copied by reference (not cloned). If you absolutely need clones, consider serializing the function source, but this is rarely safe.
  • This approach preserves property descriptors and handles circular refs using WeakMap.

Real-World Example & Tips

  • Use structural sharing (immutable updates) in Redux/React instead of deep cloning whole state trees.
  • If you only mutate top-level properties, shallow clone + targeted nested updates is far cheaper.
  • For serialization (transport/storage), create a custom serializer that encodes Dates and Maps.

Quick Practice

Create an object with a circular reference and verify deepClone(obj) returns a structurally equal but independent copy.

Summary

Deep cloning is complex but solvable: detect types, handle circular refs, and respect descriptors. Prefer selective cloning and immutable patterns for large apps.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

Why not use JSON.parse(JSON.stringify(obj))?

It fails for Dates, functions, undefined, RegExp, Maps, Sets, and circular references.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement