Skip to main content

Immutable and mutable data

Mutable data can be changed after it has been created, while immutable data cannot be changed: a new value is produced instead. In JavaScript primitives are immutable, while objects, arrays and functions are mutable.

Theory

TL;DR

  • Mutable: the object can be edited after creation: object, array, function, Map, Set.
  • Immutable: the value cannot be edited, only a new one can be created: every primitive.
  • const pins the reference, not the contents of the object, so const user = {} still allows user.name = '...'.
  • "Changing" a string or a number always creates a new value, the old one stays untouched.
  • Object.freeze() makes an object immutable at the top level, nested ones need a deep freeze.

Quick example

javascript
// mutable const user = { name: 'Tim' }; user.name = 'Alex'; console.log(user); // { name: 'Alex' } // immutable let a = 'Hello'; a[0] = 'J'; console.log(a); // "Hello", nothing changed

Definitions

TermMeaningThe essence
Mutablechangeablean object that can be modified after it is created
Immutableunchangeabledata that cannot be modified, you can only create new data

Mutable data

Objects and arrays in JavaScript are mutable structures.

javascript
const user = { name: 'Tim' }; user.name = 'Alex'; // we modify the object console.log(user); // { name: 'Alex' }

Even though user is declared with const, its contents (the object) can be modified, because const forbids changing the reference itself, not the data it points at.

The same goes for an array:

javascript
const numbers = [1, 2, 3]; numbers.push(4); console.log(numbers); // [1, 2, 3, 4]

Arrays are mutable, since we can add, remove and change elements.

Immutable data

Primitives in JavaScript are immutable. They are: string, number, boolean, null, undefined, symbol, bigint.

javascript
let a = 'Hello'; a[0] = 'J'; // an attempt to modify the string console.log(a); // "Hello", unchanged

Strings are immutable: "changing" one creates a new string.

The same with numbers:

javascript
let x = 5; let y = x; y = y + 1; console.log(x); // 5 console.log(y); // 6

Numbers are immutable too, they cannot be "changed", only a new value can be created.

How that looks in memory:

Data typeMutabilityWhere it is storedBehaviour
Primitive (string, number, boolean and others)ImmutableStacka new value is created on "change"
Object, array, functionMutableHeapmodified through the reference
javascript
let name = 'Ann'; name = name + 'a';
text
STACK: +------------------+ | name = "Ann" | <- the old string | name = "Anna" | <- the new string (created from scratch) +------------------+

The string "Ann" is not modified, a new string "Anna" is created.

Why it matters

First, the behaviour on copying:

javascript
const user1 = { name: 'Tim' }; const user2 = user1; user2.name = 'Alex'; console.log(user1.name); // "Alex", both changed (mutable)

Second, reactive frameworks (React, Redux, Vue and others). Immutability is a key principle there:

  • it lets you track state changes by comparing references;
  • it makes undo/redo straightforward;
  • it makes the code more predictable.

An example of the React approach:

javascript
// bad (mutating the state directly) state.user.age++; // good (an immutable update) setState({ ...state, user: { ...state.user, age: state.user.age + 1 } });

How to make an object immutable by hand

javascript
const user = Object.freeze({ name: 'Tim', age: 25 }); user.age = 30; // will not work console.log(user.age); // 25

Object.freeze() makes an object immutable at the top level. Nested properties have to be "deeply frozen":

javascript
function deepFreeze(obj) { Object.keys(obj).forEach(key => { if (typeof obj[key] === 'object' && obj[key] !== null) { deepFreeze(obj[key]); } }); return Object.freeze(obj); } const data = deepFreeze({ user: { name: 'Tim', skills: ['JS'] } }); data.user.name = 'Alex'; // will not change

The summary table:

CategoryExamplesMutabilityBehaviour
Immutablestring, number, boolean, null, undefined, symbol, bigintcannot be changeda new copy is created
Mutableobject, array, function, Map, Setcan be changedmodified "in place"

In short:

  • Immutable: cannot be changed, only a new value can be created.
  • Mutable: can be changed "in place".
  • Primitives are immutable, objects and arrays are mutable.
  • Immutability makes code more reliable, especially in React and Redux.

Common mistakes

  • Confusing const with immutability. const is about reassigning the variable, not about the contents of the object.
  • Assuming Object.freeze() protects the whole structure. It is shallow, nested objects stay mutable.
  • Not noticing that in non-strict mode a write to a frozen object is silently ignored, while under 'use strict' it throws a TypeError.
  • Mutating state in React (state.items.push(x)) and then wondering why the component did not re-render: a reference comparison sees no difference.
  • Believing array methods are immutable. push, splice, sort and reverse mutate the original; the immutable counterparts are concat, slice, toSorted and toReversed.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.