What are Pure Functions?
A pure function is a function that always returns the same output for the same input, and has no side effects. This means it doesn't modify variables outside its scope, doesn't change its arguments, and doesn't do I/O like reading files or making network requests.
// Pure function
function add(a, b) {
return a + b;
}
// Impure function — depends on external state
let taxRate = 0.1;
function calculateTax(amount) {
return amount * taxRate; // Changes if taxRate changes
}
// Impure function — modifies its argument
function addItem(cart, item) {
cart.push(item); // Mutates the input!
return cart;
}
Why Pure Functions Matter
Pure functions are easier to test, debug, and reason about. You don't need to worry about what happened before or what will happen after — just look at the inputs and outputs.
// Easy to test — no setup, no mocking
function multiply(a, b) {
return a * b;
}
console.log(multiply(2, 3)); // Always 6
console.log(multiply(2, 3)); // Still 6 — deterministic!
Avoiding Side Effects
Instead of mutating data, create new copies. The spread operator and Object.assign help you do this without changing the originals.
// Impure — mutates the array
function addItemToCart(cart, item) {
cart.push(item);
return cart;
}
// Pure — returns a new array
function addItemToCart(cart, item) {
return [...cart, item];
}
const cart1 = ["shirt"];
const cart2 = addItemToCart(cart1, "pants");
console.log(cart1); // ["shirt"] — unchanged
console.log(cart2); // ["shirt", "pants"]
Try it Yourself →
Pure Functions in Practice
Here's a practical example: a form validator that uses pure functions for each validation rule.
const isRequired = (value) => value.trim() !== "";
const isEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
const minLength = (min) => (value) => value.length >= min;
const validators = [
{ field: "name", rules: [isRequired] },
{ field: "email", rules: [isRequired, isEmail] },
{ field: "password", rules: [isRequired, minLength(8)] },
];
Summary
Pure functions are predictable and testable. Always return new values instead of mutating inputs, and avoid depending on external state. Your code will be much easier to maintain.