CPCODELAB
JavaScript

Higher-Order Functions and Function Composition

11 min read

Higher-Order Functions

A higher-order function is a function that either accepts another function as an argument, returns a function, or both. Array.prototype.map, filter, and reduce are the classic examples, but you can build your own.

js
// A HOF that returns a function (factory pattern)
function multiplier(factor) {
  return (n) => n * factor;
}
const double = multiplier(2);
const triple = multiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

// A HOF that accepts a function
function repeat(fn, times) {
  for (let i = 0; i < times; i++) fn(i);
}
repeat(console.log, 3); // 0, 1, 2

Function Composition

Composition chains functions together so that the output of one becomes the input of the next. A compose utility applies functions right-to-left; pipe applies them left-to-right (which reads more naturally for most people).

js
// pipe: left-to-right composition
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);

const trim    = (s) => s.trim();
const lower   = (s) => s.toLowerCase();
const noSpace = (s) => s.replace(/\s+/g, "-");

const slugify = pipe(trim, lower, noSpace);

console.log(slugify("  Hello World  ")); // "hello-world"

Partial Application and Currying

Partial application fixes some arguments of a function in advance. Currying transforms a multi-argument function into a chain of single-argument functions. Both patterns enable reuse and cleaner pipelines.

js
// Partial application with bind
function add(a, b) { return a + b; }
const add10 = add.bind(null, 10);
console.log(add10(5)); // 15

// Curried add
const curriedAdd = (a) => (b) => a + b;
const add5 = curriedAdd(5);
console.log(add5(3)); // 8

// Useful in pipelines
const prices = [10, 20, 30];
const addVAT = curriedAdd(0.2); // not quite right — illustrative
const withTax = prices.map((p) => p * 1.2);

Higher-order functions and composition are the foundation of functional programming in JavaScript. Libraries like Ramda and lodash/fp make heavy use of these patterns. Even without a library, inlining small pipe or compose helpers keeps transformation logic clean and testable.

Ready to test yourself?
Practice JavaScript— quiz & coding exercises