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.
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.
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