Shallow vs Deep Copy
Shallow copy duplicates top-level properties but shares nested references. Deep copy creates entirely independent copies at all levels.
Side-by-Side Comparison
| Feature | Shallow Copy | Deep Copy |
|---|---|---|
| Nesting depth | Top level only | All levels |
| Shared references | Yes (nested objects) | No — fully independent |
| Performance | Fast (O(n) top-level props) | Slower (traverses entire graph) |
| Best method | Spread (...) or Object.assign() | structuredClone() |
| Handles functions | Yes (copies reference) | No (structuredClone throws) |
Code Examples
Shallow Copy
- Copies only the top level of properties
- Nested objects/arrays still share references
- Methods: spread (...), Object.assign(), Array.slice()
- Fast — only one level of copying
const original = { a: 1, nested: { b: 2 } }
const shallow = { ...original }
shallow.a = 99 // independent
shallow.nested.b = 99 // MUTATES original!
console.log(original.nested.b) // 99 — shared reference!
// Array shallow copy
const arr = [1, [2, 3]]
const copy = [...arr]
copy[1].push(4) // original[1] is now [2, 3, 4]Deep Copy
- Copies ALL levels recursively
- No shared references — fully independent
- Methods: structuredClone(), JSON.parse(JSON.stringify())
- Slower — must traverse entire object graph
const original = { a: 1, nested: { b: 2 } }
// Modern approach (recommended)
const deep = structuredClone(original)
deep.nested.b = 99
console.log(original.nested.b) // 2 — independent!
// JSON approach (limited — no functions, Dates, etc.)
const jsonCopy = JSON.parse(JSON.stringify(original))
// structuredClone handles: Date, Map, Set, RegExp, ArrayBuffer
// structuredClone CANNOT handle: functions, DOM nodes, SymbolsWhen to Use Which
Shallow Copy
When the object has only primitive properties, or when you intentionally want nested objects to stay shared (performance optimization).
Deep Copy
When you need a fully independent copy — state management (Redux), undo/redo systems, or anytime mutation of the copy must not affect the original.
Common Mistakes
- Assuming spread creates a deep copy — it only copies one level deep
- Using JSON.parse(JSON.stringify()) for deep copy — it drops functions, undefined, Infinity, NaN, Dates (become strings), and circular references throw
- Not knowing about structuredClone() — it's the modern, built-in solution available in all modern browsers and Node.js 17+
Interview Questions
What are the limitations of JSON-based deep copy?
It drops: functions, undefined, Symbol keys, Infinity/NaN (become null), Date objects (become strings), Map/Set (become {}), RegExp (become {}), and it throws on circular references. structuredClone handles most of these correctly.
Implement a deep clone function
Recursively copy: check if value is null/primitive (return as-is), handle arrays (map with recursive call), handle objects (Object.entries + recursive call). For production, handle Date, Map, Set, and circular references with a WeakMap.