Understanding Object Mutability, Shallow vs Deep Copy, and the Power of Immer in JavaScript
Alifa Ara Heya

Alifa Ara Heya @alifa_ara_heya

About: I document what I learn—mostly to help myself remember. But also, to help others avoid the same mistakes. 😅 Learning Full Stack development.

Joined:
Sep 4, 2024

Understanding Object Mutability, Shallow vs Deep Copy, and the Power of Immer in JavaScript

Publish Date: Jun 27 '25
0 0

In JavaScript, objects are mutable. This means if you assign an object to a new variable, both variables refer to the same memory. Any change made through one will affect the other.

Let's explore what this means — and how to avoid unintended side effects using techniques like shallow copy, deep copy, and Immer.


🔁 Problem: Object Mutability

const employee = {
  name: "Mir",
  address: {
    country: "Bangladesh",
    city: "Dhaka",
  },
};

const employee2 = employee;
employee2.name = "Mezba";

console.log(employee.name); // "Mezba" ❗ Unexpected mutation
Enter fullscreen mode Exit fullscreen mode

employee2 and employee point to the same object. Changing employee2 affects employee.


🧪 Solution 1: Shallow Copy with Spread Operator

const employee2 = {
  ...employee,
  name: "Mezba",
};

employee2.address.city = "Chittagong";

console.log(employee.address.city); // "Chittagong" ❗ still mutated!
Enter fullscreen mode Exit fullscreen mode

This only copies the top-level fields — nested objects like address are still shared.


🌊 Solution 2: Manual Deep Copy (One Level Down)

const employee2 = {
  ...employee,
  name: "Mezba",
  address: {
    ...employee.address,
    city: "Chittagong",
  },
};

console.log(employee.address.city); // "Dhaka" ✅
Enter fullscreen mode Exit fullscreen mode

We manually copy nested structures to break the shared reference.


🧱 Solution 3: Structured Clone (Modern Browsers)

const employee2 = structuredClone(employee);
employee2.name = "Mezba";
employee2.address.city = "Chittagong";

console.log(employee.address.city); // "Dhaka" ✅
Enter fullscreen mode Exit fullscreen mode

structuredClone() performs a deep copy automatically.
⚠️ Browser support: Modern browsers only (Chrome 98+, Node.js 17+)


🛠️ Solution 4: Deep Copy Using Immer

Immer lets you write mutative code that produces immutable updates.

🔧 Step 1: Install Immer

npm install immer
Enter fullscreen mode Exit fullscreen mode

📦 Step 2: Use produce to Make Safe Updates

import { produce } from "immer";

const employee = {
  name: "Mir",
  address: {
    country: "Bangladesh",
    city: "Dhaka",
  },
};

const employee2 = produce(employee, (draft) => {
  draft.name = "Mezba";
  draft.address.city = "Chittagong";
});

console.log(employee);
// Output: { name: 'Mir', address: { country: 'Bangladesh', city: 'Dhaka' } }

console.log(employee2);
// Output: { name: 'Mezba', address: { country: 'Bangladesh', city: 'Chittagong' } }
Enter fullscreen mode Exit fullscreen mode

✅ Clean, concise, and powerful. Perfect for managing immutable state in tools like Redux.


📌 Summary Table

Technique Type Handles Nested? Notes
... spread Shallow Copy Only copies top-level
Manual nested spread Partial Deep ✅ (Manual) Tedious for deep structures
structuredClone() Deep Copy Browser/Node support required
Immer (produce) Deep Copy Cleaner syntax for immutable logic

🧠 Final Thoughts

  • Use shallow copy for flat objects.
  • Use structuredClone or Immer for deeply nested updates.
  • Immer is especially useful in React state management scenarios where immutability is key.

This post was crafted with a little help from AI 🤖
✍️ If you found this helpful, feel free to share or comment below. Happy coding!

Comments 0 total

    Add comment