Higher-Order Functions, Currying & Functional Patterns
20 min read
Higher-Order FunctionsCurryingPartial ApplicationCompositionPure FunctionsMemoizationMap Filter Reduce
Functions as First-Class Citizens
In JavaScript, functions are values. They can be assigned to variables, passed as arguments, and returned from other functions.
Higher-Order Functions
A function that takes a function as an argument or returns a function.
// Takes a function
[1, 2, 3].map(x => x * 2); // [2, 4, 6]
[1, 2, 3].filter(x => x > 1); // [2, 3]
[1, 2, 3].reduce((sum, x) => sum + x, 0); // 6
// Returns a function
function multiplier(factor) {
return (number) => number * factor;
}
const double = multiplier(2);
double(5); // 10Map, Filter, Reduce Cheat Sheet
| Method | Returns | Use When |
|---|---|---|
map() | New array (same length) | Transform each element |
filter() | New array (≤ length) | Keep elements matching condition |
reduce() | Single value | Accumulate into one result |
forEach() | undefined | Side effects only (avoid) |
find() | First match or undefined | Find one element |
some() | boolean | At least one matches |
every() | boolean | All match |
Currying
Transforming a function with multiple arguments into a series of functions each taking one argument.
// Non-curried
function add(a, b, c) { return a + b + c; }
add(1, 2, 3); // 6
// Curried
function curriedAdd(a) {
return (b) => (c) => a + b + c;
}
curriedAdd(1)(2)(3); // 6
// Practical: Creating reusable validators
const isGreaterThan = (min) => (value) => value > min;
const isAdult = isGreaterThan(17);
isAdult(21); // true
isAdult(15); // falsePartial Application
function log(level, timestamp, message) {
console.log(`[${level}] ${timestamp}: ${message}`);
}
// Partially apply the level
const errorLog = log.bind(null, "ERROR");
errorLog(Date.now(), "Server crashed"); // [ERROR] 1234567890: Server crashed
// Using closures
const createLogger = (level) => (msg) => log(level, new Date().toISOString(), msg);
const warn = createLogger("WARN");
warn("Memory usage high"); // [WARN] 2026-02-15T...: Memory usage highFunction Composition
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x);
const trim = (s) => s.trim();
const lower = (s) => s.toLowerCase();
const split = (s) => s.split(" ");
const processInput = pipe(trim, lower, split);
processInput(" Hello World "); // ["hello", "world"]Pure Functions & Side Effects
| Pure Function | Impure Function |
|---|---|
| Same input → same output | Output depends on external state |
| No side effects | Modifies external state (DOM, DB, etc.) |
| Easy to test | Hard to test |
Math.max(1,2) | Math.random() |
Memoization
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveFib = (n) => n <= 1 ? n : expensiveFib(n-1) + expensiveFib(n-2);
const fastFib = memoize(expensiveFib);
fastFib(40); // Instant after first call