Immutability & Pure Functions

The foundations of predictable code. Learn how to write safe, side-effect-free functions and avoid the nightmare of unintended data mutations.

JavaScript7 min readConcept 58 of 63

The Rules of Predictability

A **Pure Function** must satisfy two rules: 1) Given the exact same inputs, it will always return the exact same output. 2) It produces zero side effects (no DOM manipulation, no network calls, no modifying external variables).

**Immutability** means that once a piece of data is created, it cannot be changed. If you need to update it, you must create a brand new copy with the updated values.

Preventing Spooky Action at a Distance

If you pass an object into a function, and that function silently mutates a property on the object, it affects the rest of your application. This leads to bugs that are incredibly difficult to track down.

By enforcing pure functions and immutable data, your code becomes highly testable, predictable, and safe for concurrent execution.

Making Copies in JavaScript

JavaScript objects and arrays are mutable by default. To enforce immutability, you must use the spread operator (...) or array methods like .map() and .filter() which return *new* arrays rather than modifying the original.

javascript // Impure (Mutates original) function addRole(user) { user.role = 'admin'; return user; }

javascript // Pure (Returns a new copy) function addRole(user) { return { ...user, role: 'admin' }; }

Impure vs Pure Pipelines

Study the architecture diagram below. Notice how the Impure function reaches outside of its scope to modify a global variable, creating a dangerous side effect, while the Pure function is completely self-contained.

The Architecture of Purity

Impure
let user = { role: 'guest' };

function makeAdminImpure() {
// Side effect: mutates global state
user.role = 'admin';
}
Pure
function makeAdminPure(u) {
// No side effects: returns new copy
return { ...u, role: 'admin' };
}
💀
Global Memory
let user = {
role: 'guest'
role: 'admin'
}
↑ Mutates ↑
makeAdminImpure()
Reaches out of scope to modify global state.
VS
🛡️
Input Arg
const u = {
role: 'guest'
}
Safe
↓ Reads & Copies ↓
makeAdminPure(u)
Self-contained.
Returns New:
role: 'admin'
iThe Pure Function uses the spread operator ...u to safely copy the data, leaving the original memory entirely untouched.

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1Which of the following makes a function IMPURE?
  2. 2Why is `Array.prototype.push()` considered a mutating (impure) operation?
  3. 3A function takes `x` and returns `x + Math.random()`. Is this a pure function?

Remember this

  • A **Pure Function** has two rules: Same input always equals same output, and ZERO side effects.
  • Side effects include: mutating external variables, making HTTP requests, and modifying the DOM.
  • **Immutability** dictates that data should not be changed after creation. You must create updated copies instead.
  • Use the spread operator (...) or methods like .map() and .filter() to create shallow copies of objects and arrays.
  • React components and Redux reducers strictly require pure functions and immutable data to operate correctly.

Done with this concept?

Mark it complete to track your progress. No login needed.