Functionsintermediate
Pure Functions and Side Effects
Functions that always return the same output for the same input and don't modify anything outside themselves, versus functions that mutate state or perform I/O.
A pure function returns the same output for the same input and changes nothing outside itself.
A pure function is like a vending machine that dispenses the exact same snack every time you press the same button, using only the button press as input — no memory of previous purchases, no side conversations with other machines, and pressing the same button twice never changes anyone else's snack.
Key Concepts
1
// pure
const add = (a, b) => a + b;
const withTax = (p) => ({ ...p, price: p.price * 1.18 });2
// impure -- mutates its argument
const addTax = (p) => { p.price *= 1.18; return p; };3
// impure -- depends on outside state
let rate = 1.18;
const apply = (p) => p * rate;4
// impure -- performs I/O
const save = (p) => db.insert(p);5
Two properties, and both are needed. Same input, same output. No observable effect elsewhere.
6
Why it matters practically, rather than as a principle.
7
Testable. A pure function needs no setup and no mocks. Call it, check the return value.
8
Cacheable. If the output depends only on the input, the result can be memoised safely.
9
Safe to reorder and parallelise. Nothing depends on when it ran.
10
Readable. Everything it does is in its signature and its return.
11
Mutation is the side effect that bites most often.
const sorted = items.sort(); // sorts items IN PLACE
const sorted = [...items].sort(); // a copy12
sort, reverse, splice, push and shift all mutate. map, filter, slice and concat do not.
Knowing which is which prevents a whole class of bug where a function returns the right answer and quietly
changes the caller's array.
sortreversesplicepushshift
13
Newer methods toSorted, toReversed and with are the non-mutating versions, added for exactly this
reason.
toSortedtoReversedwith
14
You cannot make everything pure, and it is not the goal. A program that reads nothing and writes nothing
does nothing.
15
The useful arrangement is to push effects to the edges: pure functions for the logic, with I/O and mutation
in a thin layer around them.
16
// the logic is pure and testable
const nextState = reduce(state, action);17
// the effect is separate
render(nextState);18
Where this shows up. Redux reducers must be pure, React requires render to be pure, and memoisation is
only correct on a pure function. Those rules are not style preferences — they are the conditions those
systems rely on to work.
19
What the interviewer is probing.1. "What makes a function pure?" Probing: the two conditions. Stalls: "It returns a value."
Moves up: the same input always gives the same output, and it has no observable side effect — no
I/O, no mutation of anything outside it.
20
2. "Why do pure functions matter in practice?" Probing: the payoff. Stalls: "They are
elegant." Moves up: they are testable without setup, cacheable, and safe to reorder or
parallelise.
21
3. "Is a function reading a module-level constant pure?" Probing: the boundary. Stalls: "No,
it reads outside." Moves up: yes if the value never changes; purity is about observable behaviour,
not lexical isolation.
22
4. "Where do side effects belong?" Probing: architecture. Stalls: "Anywhere." Moves up:
pushed to the edges — a pure core with I/O at the boundary, which is what makes the core testable.