Shallow Clone vs Deep Clone in JavaScript

Understanding object cloning and immutability concepts

By Hank Kim

Shallow Clone vs Deep Clone in JavaScript

Understanding object cloning and immutability concepts

Shallow Clone vs Deep Clone

In this document, I want to explain the difference between shallow clone and deep clone in JavaScript, why cloning matters, and how to perform it correctly with code examples.

1. Shallow Clone

A shallow clone copies only the first level of properties. Nested objects and arrays are not duplicated — instead, their references are copied. This means the original and the copy still point to the same nested structures.

Example: Object Spread

const obj = {
  name: "Hank",
  address: { city: "Leeds" },
};

const copy = { ...obj }; // Shallow clone

copy.name = "Kim";
console.log(obj.name); // "Hank" ✅ unaffected

copy.address.city = "London";
console.log(obj.address.city); // "London" ❌ original changed

Example: Object.assign

const obj = { name: "Hank", address: { city: "Leeds" } };
const copy = Object.assign({}, obj);

copy.address.city = "London";
console.log(obj.address.city); // "London" ❌ still changes original

👉 Shallow clone works for top-level values but does not protect nested objects or arrays.


2. Deep Clone

A deep clone duplicates the entire structure, including nested objects and arrays. The result is completely independent of the original object.

const obj = {
  name: "Hank",
  address: { city: "Leeds" },
};

const deepCopy = structuredClone(obj);

deepCopy.address.city = "London";
console.log(obj.address.city); // "Leeds" ✅ safe

Example: Nested Array

const arr = [
  [1, 2],
  [3, 4],
];
const deepCopy = structuredClone(arr);

deepCopy[0][0] = 99;
console.log(arr[0][0]); // 1 ✅ unaffected

3. Why It Matters

  1. State Management and Immutability

    • In React or Redux, state must not be mutated directly.
    • Shallow clone may share references, causing unintended mutations.
    • Deep clone ensures a new, independent object for safe state updates.
  2. Data Integrity

    • Prevents accidental changes to original data when transformations are needed.
    • Useful when you want to keep server responses intact but create derived versions.
  3. Bug Prevention

    • Avoids subtle bugs caused by shared references in deeply nested structures.

4. Deep Clone Methods

1. structuredClone (Modern API)

const original = {
  user: { name: "Hank", info: { age: 25 } },
};
const clone = structuredClone(original);

clone.user.info.age = 30;
console.log(original.user.info.age); // 25 ✅
  • Supports most built-in types (Objects, Arrays, Dates, Maps, Sets).
  • Fast and safe.
  • Not available in very old environments.

2. JSON Serialization (Classic Trick)

const obj = { name: "Hank", date: new Date() };
const clone = JSON.parse(JSON.stringify(obj));

console.log(clone.name); // "Hank"
console.log(clone.date); // string, not Date ❌
  • Limitations:

    • Cannot clone functions
    • Loses Date, Map, Set, undefined, circular references

3. Manual Recursive Clone (Custom Implementation)

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  if (Array.isArray(obj)) {
    return obj.map((item) => deepClone(item));
  }
  const clone = {};
  for (const key in obj) {
    clone[key] = deepClone(obj[key]);
  }
  return clone;
}

const original = { user: { name: "Hank", hobbies: ["coding", "music"] } };
const copy = deepClone(original);

copy.user.hobbies[0] = "travel";
console.log(original.user.hobbies[0]); // "coding" ✅

Tags: JavaScript