Deep vs. Shallow Copy in JavaScript: A Practical Guide

November, 17th 2024 2 min read

Copying objects and arrays is a core skill in JavaScript development, especially when dealing with immutable patterns, state management, and nested data structures. This guide explains the difference between shallow copy and deep copy, shows how to implement both, and provides practical examples and best‑use cases.

Read also: How to Clone Complex JavaScript Objects with structuredClone()

What Is the Difference?

Shallow Copy

A shallow copy duplicates only the top-level properties. Any nested objects remain references to the original.

  • Fast and lightweight
  • Not safe when modifying nested objects

Deep Copy

A deep copy fully duplicates the entire object structure recursively. Changing any nested values does not affect the original.

  • Safe for immutable logic
  • More resource‑intensive

Deep Copy Methods

1. JSON.stringify + JSON.parse

js
function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

✔ Simple
✔ Good for plain objects
✘ Breaks on Date, Map, Set, RegExp, functions
✘ Fails on circular references


2. Recursive Deep Copy

js
function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;

  const clone = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
}

✔ Flexible
✔ Can support circular references with extra logic
✘ More code
✘ Requires manual handling of special types


3. structuredClone (Native Deep Copy)

js
const cloned = structuredClone(original);

✔ Supports many built‑in types (Date, Map, Set, File, Blob)
✔ Fast and native
✘ Not available in old browsers


4. Lodash cloneDeep

js
import cloneDeep from 'lodash/cloneDeep';

const result = cloneDeep(data);

✔ Battle‑tested
✔ Handles edge cases and circular structures
✘ Adds dependency


Shallow Copy Methods

1. Spread Operator

js
const copy = { ...original };
const arrCopy = [...originalArray];

2. Object.assign

js
const copy = Object.assign({}, original);

3. Array slice / concat

js
const copy = originalArray.slice();
const copy2 = originalArray.concat();

4. Array.from

js
const copy = Array.from(originalArray);

⚠ Nested objects remain linked to the original.


When to Use What?

Use Shallow Copy when:

  • You only need top‑level cloning
  • You work with flat data structures
  • High performance is required

Use Deep Copy when:

  • Modifying nested structures
  • Using immutable patterns (React state, Redux, Zustand)
  • Data integrity is critical

Key Considerations

Circular References

Deep-copy methods must detect them:

js
// JSON-based methods will fail:
// TypeError: Converting circular structure to JSON

Special Object Types

For Date, RegExp, Map, Set, File, Blob → use structuredClone or Lodash.

Performance

Deep cloning large objects can be expensive. Benchmark before using in hot code paths.


Summary

MethodTypeProsCons
SpreadShallowFast, simpleShares nested refs
JSON cloneDeepSimpleBreaks on many types
RecursionDeepFlexibleComplex, slower
structuredCloneDeepFast, nativeBrowser support varies
Lodash cloneDeepDeepRobustExtra dependency

Deep and shallow copying are essential for safe, predictable data handling in JavaScript. With these techniques, you can confidently manage complex state, avoid mutation bugs, and write cleaner, more maintainable code.