javascript deep copy object: Safe Cloning Strategies for JavaScript
Master JavaScript deep copy techniques—from JSON cloning to structuredClone and custom copies. Learn data-type limits and performance tradeoffs with examples.

Deep copy in JavaScript creates a new object with recursively copied properties, so changes to the copy do not affect the original. Common approaches include structuredClone, JSON-based cloning (with caveats), and manual deep-copy functions. This guide covers the strengths, limits, and practical examples to help you choose the right method.
javascript deep copy object — What it means to clone deeply in JS
In JavaScript, a true deep copy duplicates an object and every nested object or array, so the copy has no shared references with the original. This is essential to avoid unintended mutations when you pass data through layers of your app. The topic javascript deep copy object often comes up in state management and data serialization scenarios.
// Example 1: shallow copy ( shares nested objects )
const original = { a: 1, b: { c: 2 } };
const shallow = { ...original };
console.log(shallow.b === original.b); // true
// Example 2: deep copy with JSON ( simple, but has caveats )
const jsonCopy = JSON.parse(JSON.stringify(original));
console.log(jsonCopy.b === original.b); // false
// Note: Date, undefined, functions, and circular references are not preserved
// Example 3: deep copy with structuredClone (modern environments)
const structured = structuredClone(original);
console.log(structured.b === original.b); // false- Shallow copies copy only the top level; nested objects remain references.
- JSON-based cloning is simple but lossy for dates, functions, undefined, Maps, Sets, and circular references.
- structuredClone handles many built-in types and most circular structures in modern environments.
javascript deep copy object — Methods and tradeoffs for deep copying in JS
Choosing a copying strategy depends on your data. JSON cloning is terse but loses non-JSON types. structuredClone is robust for modern runtimes but may not be available everywhere. A hand-rolled recursive deepCopy can handle plain objects/arrays and cycles with care.
// JSON-based clone (simple, lossy for non-JSON types)
const clone1 = JSON.parse(JSON.stringify(original));
// structuredClone (best general-purpose in modern runtimes)
const clone2 = structuredClone(original);
// Simple recursive clone (cycles handled via WeakMap)
function deepCopy(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
if (Array.isArray(obj)) {
const out = [];
seen.set(obj, out);
for (const item of obj) out.push(deepCopy(item, seen));
return out;
}
const out = {};
seen.set(obj, out);
for (const [k, v] of Object.entries(obj)) out[k] = deepCopy(v, seen);
return out;
}- Use JSON cloning for simple, JSON-serializable data only.
- Use structuredClone when available for broad type support.
- Implement a careful recursive clone for plain objects when you need full control.
javascript deep copy object — Handling circular references and special types
Circular references break naive deep-copy algorithms. The following approach uses a WeakMap to remember previously copied objects, preventing infinite recursion and preserving identity for cycles. It also demonstrates handling arrays and plain objects consistently.
function deepCopyWithCycles(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
if (Array.isArray(obj)) {
const arr = [];
seen.set(obj, arr);
for (const v of obj) arr.push(deepCopyWithCycles(v, seen));
return arr;
}
const res = {};
seen.set(obj, res);
for (const [k, v] of Object.entries(obj)) res[k] = deepCopyWithCycles(v, seen);
return res;
}
// Example with a circular reference
const a = { name: 'Alice' };
const b = { owner: a };
a.self = b;
const cloned = deepCopyWithCycles(a);
console.log(cloned.self.owner === cloned); // true (circular preserved in copy)- StructuredClone handles many types but not all custom types; fallbacks are essential.
- WeakMap-based clones cope with cycles but require a careful implementation.
javascript deep copy object — Working with Date, RegExp, Maps, and Sets
JSON cloning loses Date objects, RegExp, Map, Set, and custom class instances. You can clone some types by constructing new instances, or clone collections by copying their contents. A robust approach combines type checks with specialized handling for each type:
// Date and RegExp preservation
const d = new Date();
const r = /test/i;
function cloneSpecials(v) {
if (v instanceof Date) return new Date(v);
if (v instanceof RegExp) return new RegExp(v.source, v.flags);
if (v instanceof Map) return new Map(Array.from(v.entries()).map(([k, val]) => [k, typeof val === 'object' ? deepCopyWithCycles(val) : val]));
if (v instanceof Set) return new Set(Array.from(v.values()).map(x => (typeof x === 'object' ? deepCopyWithCycles(x) : x)));
return v;
}- Maps and Sets are shallow-copyable with new Map(original)/new Set(original), but their inner values may need deepCopy handling.
- Dates and RegExp require constructors to preserve type information.
javascript deep copy object — When to deep copy and alternatives
Not all data should be deeply copied. If objects are immutable by design or used for functional programming patterns, a shallow copy or reference passing can be preferable. For complex state trees, prefer a dedicated deepCopy utility that fits your data types and environment. In some cases, structural sharing or immutable data structures (like Immutable.js) can be a better long-term solution.
// Example: when to avoid deep copy
const config = { mode: 'dark', user: { name: 'Sam' } };
const shallow = { ...config }; // fine if you won't mutate nested objects
// Example: immutable pattern
function withNewName(state, name) {
return deepCopy(state); // or use an immutable library
// return { ...state, user: { ...state.user, name } }
}javascript deep copy object — Practical patterns and tips
In practice, you’ll combine strategies depending on data shape and runtime. Favor structuredClone in modern environments, fall back to a well-tested deepCopy for plain objects, and reserve JSON cloning for simple payloads. Always test with your real data, including circular references and complex types.
// Practical checklist
const payload = { a: 1, b: { c: [1,2,3], d: new Date() }, e: new Map([['k', 'v']]) };
const clone = typeof structuredClone === 'function' ? structuredClone(payload) : deepCopy(payload);
console.log(clone);Steps
Estimated time: 20-30 minutes
- 1
Identify data structure
Survey the object graph in your codebase to determine which parts require deep copying (objects, arrays, dates, maps, sets).
Tip: Map the types you must preserve in the clone. - 2
Choose a cloning strategy
Decide between JSON cloning, structuredClone, or a custom recursive function based on data types and environment.
Tip: If you need to duplicate non-JSON types, JSON cloning won't suffice. - 3
Implement a clone
Implement a function that handles the required types, addressing cycles with a WeakMap or similar cache.
Tip: Prioritize correctness over premature optimization. - 4
Test with real data
Run tests that include nested structures, dates, maps, and circular references to verify fidelity.
Tip: Add unit tests for edge cases like undefined and functions. - 5
Compare methods
Benchmark and compare memory usage and performance across methods in your target environment.
Tip: StructuredClone often offers broad type support in modern runtimes. - 6
Integrate and document
Document chosen approach and add notes on limitations for future maintainers.
Tip: Document when to switch strategies depending on environment.
Prerequisites
Required
- Required
- Basic JavaScript knowledge (objects, references)Required
- Browser or Node.js environment for testingRequired
Optional
- Optional: knowledge of Maps, Sets, Dates for advanced copyingOptional
- Optional
Keyboard Shortcuts
| Action | Shortcut |
|---|---|
| CopyCopy code or text blocks | Ctrl+C |
| PasteInsert copied content | Ctrl+V |
| Format DocumentFormat code in editor | Ctrl+⇧+F |
| Comment LineToggle line comment | Ctrl+/ |
Questions & Answers
What is the difference between deep copy and shallow copy in JavaScript?
A shallow copy duplicates the top-level object but retains references to nested objects, so changes to nested data affect both copies. A deep copy recursively duplicates everything, so the two objects are independent.
Shallow copies copy the top level only; deep copies duplicate nested data as well so both objects stay independent.
Which methods are best for deep copying objects in JavaScript?
Use structuredClone for most modern environments, JSON cloning for simple, JSON-serializable data, or implement a custom recursive copy for complex plain objects with cycles.
StructuredClone works well in modern runtimes, JSON cloning is easy but limited, and custom deep copies give you full control.
Does JSON.stringify preserve Date, Map, Set, or functions?
No. JSON.stringify converts Dates to strings, and it drops functions, Maps, Sets, and handles circular references poorly. Use other methods for complex data.
JSON cloning loses dates and maps and can't handle circular references.
Is structuredClone supported in Node and browsers?
StructuredClone is supported in modern browsers and Node 17+; older environments may require fallbacks or polyfills.
Most modern environments support structuredClone; older ones may need alternatives.
How do I handle circular references in deep copy?
Use a cache, typically a WeakMap, to track previously copied objects and return the cached copy when a cycle is encountered.
Use a WeakMap to track cycles so your copy doesn't loop forever.
Can I clone Maps or Sets deeply?
Cloning Maps or Sets can be done with new Map(original) or new Set(original); deep-copying their contents may require extra handling for nested values.
You can copy Maps and Sets, but nested values may need extra deep-copy logic.
When should I avoid deep copying altogether?
If immutability is guaranteed or data is simple, a shallow copy or direct reference may suffice. Deep copying has performance costs and complexity.
If you don't need to mutate nested data, a shallow copy is often enough and faster.
What are performance considerations for deep copying?
Deep copying can be expensive for large, nested structures. Benchmark methods in your target environment and choose the simplest method that preserves correctness.
Deep copies can be slow; test and choose a method that balances correctness and speed.
What to Remember
- Understand deep vs shallow copies to prevent mutations
- Choose cloning strategy based on data types and environment
- Avoid JSON cloning for non-JSON types like Date/Maps/Sets
- Prefer structuredClone in modern runtimes for broad type support