Q30: Implement a deep-clone utility and explain its limitations.

Difficulty:AdvancedTopic:Recursion and References

Answer

A deep clone creates a separate copy of an object's nested structure rather than sharing nested references with the original.

For supported values, the native structuredClone() API is usually preferable to a hand-written implementation. However, interview questions often ask you to implement a basic deep clone.

function deepClone(value, seen = new WeakMap()) {
  if (value === null || typeof value !== "object") {
    return value;
  }

  if (seen.has(value)) {
    return seen.get(value);
  }

  if (value instanceof Date) {
    return new Date(value.getTime());
  }

  if (value instanceof RegExp) {
    return new RegExp(value.source, value.flags);
  }

  if (value instanceof Map) {
    const clone = new Map();
    seen.set(value, clone);

    for (const [key, item] of value) {
      clone.set(deepClone(key, seen), deepClone(item, seen));
    }

    return clone;
  }

  if (value instanceof Set) {
    const clone = new Set();
    seen.set(value, clone);

    for (const item of value) {
      clone.add(deepClone(item, seen));
    }

    return clone;
  }

  if (Array.isArray(value)) {
    const clone = [];
    seen.set(value, clone);

    for (const key of Reflect.ownKeys(value)) {
      const descriptor = Object.getOwnPropertyDescriptor(value, key);

      if (descriptor && "value" in descriptor) {
        descriptor.value = deepClone(descriptor.value, seen);
      }

      Object.defineProperty(clone, key, descriptor);
    }

    return clone;
  }

  const prototype = Object.getPrototypeOf(value);
  const clone = Object.create(prototype);
  seen.set(value, clone);

  for (const key of Reflect.ownKeys(value)) {
    const descriptor = Object.getOwnPropertyDescriptor(value, key);

    if (descriptor && "value" in descriptor) {
      descriptor.value = deepClone(descriptor.value, seen);
    }

    Object.defineProperty(clone, key, descriptor);
  }

  return clone;
}

const original = {
  user: { name: "Suriya" },
  numbers: [1, 2, 3]
};

const copy = deepClone(original);
copy.user.name = "Alex";

console.log(original.user.name); // Suriya
console.log(copy.user.name); // Alex

Explanation

The WeakMap tracks already-visited objects. This prevents infinite recursion when the input contains circular references and preserves repeated references within the cloned object graph.

The implementation supports ordinary objects, arrays, dates, regular expressions, maps, sets, symbol keys, property descriptors, and circular references. However, it is not a universal cloning algorithm: functions are returned by reference, custom classes and built-in objects may need specialized handling, and objects with internal slots or special construction requirements may not be correctly recreated.

For general-purpose cloning of supported structured-cloneable values, use structuredClone(value) when available.

Key Takeaways
  • Deep cloning separates nested references and must handle cycles when they are possible.
  • A general-purpose clone must account for built-in types, property descriptors, and special object behavior.