Functional Programming Techniques in JavaScript
Practical functional programming patterns: compose, pipe, map, filter, reduce, and more
Introduction
Functional programming (FP) emphasizes immutability, pure functions, and function composition. JavaScript supports FP naturally with first-class functions and array methods. Master these techniques to write cleaner, more predictable code.
Core Concepts
Immutability
Never modify data; create new copies instead.
// ❌ Mutation
const user = { name: 'John', age: 30 };
user.age = 31;
// ✅ Immutability
const user = { name: 'John', age: 30 };
const updatedUser = { ...user, age: 31 };
Pure Functions
Always return the same output for the same input, with no side effects.
// ✅ Pure
const add = (a, b) => a + b;
// ❌ Impure
let counter = 0;
const increment = () => ++counter;
Function Composition
compose
Execute functions right-to-left.
const compose =
(...functions) =>
(data) =>
functions.reduceRight((value, func) => func(value), data);
const addOne = (x) => x + 1;
const double = (x) => x * 2;
const square = (x) => x * x;
const transform = compose(square, double, addOne);
transform(3); // ((3 + 1) * 2)² = 64
pipe
Execute functions left-to-right (more intuitive).
const pipe =
(...functions) =>
(data) =>
functions.reduce((value, func) => func(value), data);
const transform = pipe(addOne, double, square);
transform(3); // ((3 + 1) * 2)² = 64
Array Operations
map
Transform each element.
const users = [{ name: 'John' }, { name: 'Jane' }];
const names = users.map((user) => user.name);
filter
Select elements matching a condition.
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter((n) => n % 2 === 0);
reduce
Accumulate values into a single result.
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, n) => acc + n, 0);
Handling Null and Undefined
Optional Chaining
const street = user?.address?.street;
Nullish Coalescing
const name = userName ?? 'Anonymous';
Practical Examples
Data Transformation Pipeline
const processOrders = pipe(
(orders) => orders.filter((order) => order.status === 'completed'),
(orders) =>
orders.map((order) => ({
id: order.id,
total: order.items.reduce((sum, item) => sum + item.price, 0),
})),
(orders) => orders.sort((a, b) => b.total - a.total),
(orders) => orders.slice(0, 10),
);
Best Practices
Keep Functions Small
Avoid Side Effects
Use Descriptive Names
Conclusion
Functional programming techniques lead to cleaner, more predictable code. Start with pure functions and array methods, then explore composition.