Immutability in JavaScript: producing a new value instead of changing the old one

Immutability means never modifying an existing value but producing a changed copy instead. Copies, freezing and methods that do not mutate.
3 min read
Believemy logo

An array modified in one part of the code can shift under the feet of another part that was already holding it. The bug is silent, shows up far from its cause, and survives careful reading.

Immutability cuts that scenario short with a simple discipline: nothing is modified, a new value is produced.


Definition

Immutability is the principle that a value, once created, is never modified again. Every change goes through creating a copy that carries it. The old version stays intact for whoever was holding it.

JAVASCRIPT
const cart = ["keyboard", "mouse"];
const withScreen = [...cart, "screen"];

console.log(cart);       // [ 'keyboard', 'mouse' ]
console.log(withScreen); // [ 'keyboard', 'mouse', 'screen' ]

const profile = { name: "Ada", city: "London" };
const moved = { ...profile, city: "Paris" };

console.log(profile.city); // London
console.log(moved.city);   // Paris

Spread (...) does all the work: it copies the contents into a fresh structure, and whatever is written after it replaces what was just copied.


The same move, in an immutable version

Every operation that changes things in place has a counterpart that returns a copy. This three-column table covers the four everyday cases.

NeedVersion that mutatesVersion that copies
Append at the endlist.push(x)[...list, x]
Remove an itemlist.splice(i, 1)list.filter(...)
Sortlist.sort()list.toSorted()
Change a fieldobj.field = v{ ...obj, field: v }


Object.freeze and its limit

const prevents reassigning a name, not modifying what it holds. Object.freeze() goes further, but stops at the first level.

JAVASCRIPT
const config = Object.freeze({ lang: "en", options: { sound: true } });

console.log(Object.isFrozen(config));         // true
console.log(Object.isFrozen(config.options)); // false, freezing is shallow

config.options.sound = false;
console.log(config.options.sound);            // false
Good to know

Writing config.lang = "fr" is silently ignored in a classic script, and throws a TypeError in a module. Freezing protects, but not the same way everywhere.


Frequently asked questions

Question

Is copying all the time expensive?

A shallow copy only duplicates the first level: nested values are shared, not recreated. On lists of a few thousand items, the cost is nothing compared to the hours spent chasing an unexpected Mutation. The real risk would be systematic deep copying, which is rarely needed.


Question

Does const make a value immutable?

No, and that is the most widespread confusion. const forbids reassigning the name, nothing more. An array declared with const happily accepts push(), because the variable still points at the same array. See Reference vs value for the details.


Question

Why do modern interfaces care so much about it?

Because a rendering library detects a change by comparing two references. If the object was modified in place, the old and the new one are identical and nothing refreshes. Our React course comes back to this from the very first state update, where the rule becomes concrete.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.