CPCODELAB
JavaScript

Immutability Patterns

8 min read

Why Immutability Matters

Immutability means never modifying a value in place — instead, you create a new value with the desired changes. Immutable data is easier to reason about, makes change-detection trivial (reference equality), and prevents whole categories of bugs caused by accidental mutation.

JavaScript primitives are already immutable. Objects and arrays are mutable by default, so you must be deliberate about protecting them.

Immutable Object Updates

js
const user = { name: "Alice", age: 30, role: "user" };

// BAD — mutates the original
user.role = "admin";

// GOOD — spread creates a new object
const adminUser = { ...user, role: "admin" };
console.log(user.role);      // "user" — unchanged
console.log(adminUser.role); // "admin"

// Nested update — must spread at every level
const state = { user: { name: "Alice", prefs: { theme: "light" } } };
const darkState = {
  ...state,
  user: { ...state.user, prefs: { ...state.user.prefs, theme: "dark" } }
};

Immutable Array Updates

js
const items = ["a", "b", "c", "d"];

// Add (spread)
const added = [...items, "e"];

// Remove by index (filter)
const removed = items.filter((_, i) => i !== 1); // ["a","c","d"]

// Update at index (map)
const updated = items.map((v, i) => (i === 2 ? "C" : v));
// ["a","b","C","d"]

// Sort without mutating (ES2023)
const sorted = items.toSorted();
const reversed = items.toReversed();

Object.freeze(obj) makes an object shallowly immutable — top-level properties cannot be reassigned, but nested objects are still mutable. For deep immutability at scale, consider libraries like Immer, which lets you write mutating-style code that produces immutable updates under the hood.

React state, Redux reducers, and many other UI patterns require immutable updates. Mastering spread-based patterns now will make those frameworks feel natural.

Ready to test yourself?
Practice JavaScript— quiz & coding exercises