Mutable vs Immutable, Side by Side

mutable.js — same object, contents changed const arr = [1, 2, 3]; const ref = arr; arr.push(4); console.log(ref); // [1, 2, 3, 4] — ref sees the change too, same object
immutable.js — new object, original untouched const arr = [1, 2, 3]; const newArr = [...arr, 4]; // creates a brand new array console.log(arr); // [1, 2, 3] — unchanged console.log(newArr); // [1, 2, 3, 4] — a different object in memory

In the mutable example, ref and arr point to the exact same array in memory — changing one changes what the other sees. In the immutable example, newArr is a completely separate array; the original is never touched.

Why React Cares About This So Much

React often decides whether to re-render using a fast reference comparison (oldState === newState) rather than deeply comparing every property. If you mutate state in place, the reference never changes — React sees the same object and assumes nothing happened, so it skips the re-render even though the data is actually different.

wrong.js — React won't notice this state.items.push(newItem); setState(state); // same reference — React may skip re-rendering
right.js — new reference, React notices setState({ ...state, items: [...state.items, newItem] });

const Does Not Mean Immutable

This is one of the most common misconceptions in JavaScript:

CodeWhat it actually means
const x = 5;x cannot be reassigned
const arr = [1,2,3]; arr.push(4);Allowed! const only locks the variable binding, not the array's contents
Object.freeze(obj)Actually prevents top-level property changes (but not nested objects)

What's Mutable and What's Immutable in JavaScript

TypeMutable?
StringNo — immutable; methods like .toUpperCase() return a new string
Number, BooleanNo — immutable primitives
ArrayYes — .push(), .splice(), .sort() all mutate in place
ObjectYes — properties can be added/changed/deleted directly

Immutability and Pure Functions

A pure function never mutates its inputs and always returns the same output for the same input. Immutability makes writing pure functions natural, because there's no shared mutable state to accidentally corrupt — this is also why immutability is central to functional programming and to predictable state management in Redux.

⚠️ The Performance Trade-off

Always creating new objects/arrays costs more memory and CPU than mutating in place — especially for large, deeply nested state. Libraries like Immer and Immutable.js use structural sharing (reusing the parts of the structure that didn't change) to keep immutable updates close to mutable performance.

💡 Why It's Worth the Cost

Immutability makes undo/redo, time-travel debugging, and detecting "did anything actually change?" trivial — you just compare references instead of deep-diffing entire object trees. That predictability is usually worth far more than the small extra allocation cost.

How We Research and Update This Guide

We test the underlying formula or workflow, compare outputs with reliable references, and revise examples whenever the page content changes.

  • The workflow or formula is tested directly in the tool and compared against independent reference examples.
  • Examples are kept practical so readers can verify the result without hidden assumptions.
  • Pages are revised whenever the interface, calculation flow, or surrounding guidance materially changes.

Frequently Asked Questions — Mutability vs Immutability