Write a function that deep clones an object, including nested arrays and circular references.
Return primitives as they are. For objects and arrays, create an empty copy, record it in a WeakMap so circular references reuse it, then recursively clone each property. In modern runtimes, structuredClone does this for you.
Explain it simply
The idea: if the value is not an object, there is nothing to copy. If it is an object, make an empty twin, and fill it by cloning every property the same way.
The tricky part is a circular reference, such as an object that contains itself. Without protection the function would recurse forever. The fix is a WeakMap from each original object to its clone. Before cloning an object, check whether you have already cloned it, and if so reuse that clone.
Real libraries also handle Date, Map, Set and RegExp. Here we handle Dates, arrays and plain objects.
Line by line
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);
const copy = Array.isArray(value) ? [] : {};
seen.set(value, copy);
for (const key of Object.keys(value)) {
copy[key] = deepClone(value[key], seen);
}
return copy;
}
const orig = { a: 1, b: { c: [1, 2] } };
orig.self = orig;
const copy = deepClone(orig);
copy.b.c.push(3);
console.log(orig.b.c.length); // Output: 2
console.log(copy.b.c.length); // Output: 3
console.log(copy.self === copy); // Output: true
console.log(copy === orig); // Output: falseWhat to say in the interview
"Primitives return as-is. For objects I create an empty array or object, register it in a WeakMap before recursing so circular references reuse the same clone, and then clone each key. In production I would just call structuredClone."
Complexity
Time O(n) for n total values visited. Space O(n) for the copy and the WeakMap, plus recursion depth.
Common mistakes
- Registering the clone in the WeakMap after recursing, which breaks circular references.
- Cloning functions or class instances without thinking about what should happen to them.