A pure function always returns the same output for the same input and causes no observable side effects. Pure functions are the easiest code in any codebase to test, reason about, and safely run in parallel or cache.
1Pure Functions | JavaScript Tutorial - In-Depth Guide Part 1
A pure function has two properties: given the same input, it always returns the same output, and it produces no side effects.
function add(a, b) {
return a + b; // always same output, no side effects
}Two Properties
2Pure Functions | JavaScript Tutorial - In-Depth Guide Part 2
A side effect is anything a function does besides computing its return value: mutating an argument, changing a global variable, logging, or making a network request.
let total = 0;
function addToTotal(n) {
total += n; // side effect: mutates outer variable
}What Is a Side Effect?
3Pure Functions | JavaScript Tutorial - In-Depth Guide Part 3
Mutating an argument passed into a function is a side effect too, even if the function also returns a value.
function addItem(cart, item) {
cart.items.push(item); // mutates caller's cart!
return cart;
}Mutating Arguments
4Pure Functions | JavaScript Tutorial - In-Depth Guide Part 4
The pure version of the same function returns a new object instead of mutating the one it received.
function addItem(cart, item) {
return { ...cart, items: [...cart.items, item] };
}The Pure Version
5Pure Functions | JavaScript Tutorial - In-Depth Guide Part 5
Pure functions are trivially easy to unit test, safely cacheable via memoization, and safe to run concurrently since they touch no shared state.
test('addItem returns a new cart', () => {
const cart = { items: [] };
const next = addItem(cart, 'apple');
expect(cart.items).toEqual([]); // untouched
expect(next.items).toEqual(['apple']);
});Why It Matters
6Step-by-Step Breakdown
A pure function has two properties: given the same input, it always returns the same output, and it produces no side effects.
A side effect is anything a function does besides computing its return value: mutating an argument, changing a global variable, logging, or making a network request.
Checkpoint: Does calling console.log() inside a function make that function impure?
- โYes, logging is an observable side effect
- โNo, console.log does not affect the return value
Mutating an argument passed into a function is a side effect too, even if the function also returns a value.
The pure version of the same function returns a new object instead of mutating the one it received.
Checkpoint: In the pure version of addItem, does the original cart object passed in ever get modified?
- โYes, the spread operator still mutates it
- โNo, a completely new object is returned instead
Pure functions are trivially easy to unit test, safely cacheable via memoization, and safe to run concurrently since they touch no shared state.
Next, we'll explore 'Function Composition'.
Level Up ๐
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Pure Rendering Logic Produces More Predictable Accessible Output
When the function that computes ARIA attribute values from state is pure, the same application state always renders the same accessibility tree, making assistive technology behavior consistent and easier to test automatically.
SEO Implications
- 1
Pure Rendering Functions Reduce Server-Rendering Inconsistencies
Server-side rendering that relies on pure functions to compute page markup from data avoids subtle hydration mismatches caused by hidden state or side effects, which can otherwise produce inconsistent HTML seen by crawlers versus users.
Best Practices
Isolate Side Effects at the Edges of Your Application
Keep core business logic (calculations, transformations) pure, and push I/O, DOM updates, and logging to a thin outer layer โ this maximizes the amount of easily testable code.
Never Mutate Function Arguments
Treat every argument as read-only inside a function body; return a new value instead of mutating in place, so callers are never surprised by changes to objects they still hold a reference to.
Frequent Bugs
A function that appears to just 'calculate' something actually mutates a shared array or object passed as an argument, causing distant, hard-to-trace bugs elsewhere in the app.
Audit functions that take objects/arrays as arguments for any mutation methods (push, splice, direct property assignment) and replace them with non-mutating equivalents that return new data.
Relying on `Date.now()` or `Math.random()` inside a function that is otherwise treated as pure, then being confused when tests produce different results each run.
Recognize that any function reading external, changing state (the clock, randomness, global variables) is inherently impure โ inject these as parameters instead so tests can supply fixed values.
Real-World Examples
Pure Reducer Functions in State Management
A state management library required every state-update function to be pure so it could support features like time-travel debugging and undo/redo.
function cartReducer(state, action) {
switch (action.type) {
case 'ADD_ITEM':
return { ...state, items: [...state.items, action.item] };
default:
return state;
}
}