Higher-Order Functions

A function that takes another function as input, returns one as output, or both.

What is it?

In JavaScript, functions are values — you can store them in variables, put them in arrays, and pass them around just like a number or a string. A higher-order function is simply a function that takes advantage of this: it either accepts another function as a parameter, returns a function as its result, or does both.

You've already met several: .map(), .filter(), and .reduce() are all higher-order functions, because each one accepts a callback function as an argument.

Explain like I'm 10

A higher-order function is like a manager who doesn't do the specific task themselves — they take instructions (a function) from you and apply them, or they hand you back a customized set of instructions (a function) built for a specific situation.

Examples

A function that returns a function

function multiplyBy(factor) {
  return function (n) {
    return n * factor;
  };
}

const double = multiplyBy(2);
const triple = multiplyBy(3);

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

A function that takes a function as a parameter

function applyTwice(fn, value) {
  return fn(fn(value));
}

const addOne = (n) => n + 1;

console.log(applyTwice(addOne, 5)); // 7 — addOne(addOne(5))

applyTwice doesn't know or care what fn actually does — it just applies whatever function it's given, twice. That flexibility is the whole point of accepting a function as a parameter.

How it works

Because functions are ordinary values, returning one from another function works exactly like returning a number or a string — the returned function just happens to be callable, and (thanks to closures) it remembers the variables from where it was created, like factor above.

Why does it exist?

Higher-order functions let you write general-purpose logic once (like "multiply by some factor") and customize it on demand, instead of writing a separate, nearly-identical function for every specific case.

When to use it

Reach for a higher-order function when you want to generate specialized functions from a general pattern (like multiplyBy), or when you're designing an API where the caller should supply custom behavior (like .map() accepting any transformation).

When not to use it

If a plain function with a couple of parameters would do the same job just as clearly, wrapping it in another layer of functions-returning- functions just adds indirection without benefit.

Common mistakes

  • Confusing a higher-order function with a callback — a higher-order function is the one accepting/returning functions; a callback is the function being passed in.

  • Forgetting to actually call the returned function — const double = multiplyBy(2) gives you a function, not a number.

  • Overusing function factories for cases that don't actually need customization.

Practice exercises

  1. Easy:

    Write a higher-order function add(a) that returns a function which adds a to whatever number it's given.

  2. Medium:

    Write a function compose(f, g) that returns a new function applying g then f to its input.

  3. Hard:

    Write a function debounce(fn, delay) that returns a version of fn which only runs after it hasn't been called for delay milliseconds.

Interview questions

What makes a function 'higher-order'?

It accepts another function as an argument, returns a function as its result, or both — treating functions the same way as any other value, like a number or string, rather than needing a special mechanism to work with them.

What's the difference between a higher-order function and a callback?

They're two ends of the same relationship: the higher-order function is the one that accepts or returns a function; the callback is the function being passed in to it. In arr.map(fn), map is the higher-order function, and fn is the callback.

Besides array methods, what are some built-in higher-order functions?

setTimeout/setInterval (accept a function to run later), addEventListener (accepts a handler function), and promise methods like .then() (accept functions to run on resolution/rejection) are all higher-order — they take a function as one of their arguments.

What does this log? `function greaterThan(n) { return (m) => m > n; } const greaterThan10 = greaterThan(10); console.log(greaterThan10(15)); console.log([5, 12, 8, 20].filter(greaterThan10));`

true then [12, 20] — greaterThan(10) returns a specialized function that closes over n = 10; that returned function is then reused both standalone and as a filter callback.

What is function composition, and what does `compose(f, g)` typically mean?

Combining two (or more) functions so the output of one feeds directly into the input of the next. compose(f, g) conventionally means 'apply g first, then feed its result into f' — right to left — as opposed to pipe(f, g), which usually runs them left to right.

What does this log? `const compose = (f, g) => (x) => f(g(x)); const double = (n) => n * 2; const increment = (n) => n + 1; const doubleThenIncrement = compose(increment, double); console.log(doubleThenIncrement(3));`

7 — compose(increment, double) applies double first (3 * 2 = 6), then feeds that into increment (6 + 1 = 7); despite the name doubleThenIncrement, the order inside compose runs right-to-left, which is exactly what happened.

What is currying, and how is it different from ordinary partial application?

Currying transforms a function of several arguments into a chain of functions that each take exactly one argument. Partial application is more general — fixing some arguments ahead of time and returning a function that still takes the rest, whether one at a time or several at once.

What does this log? `const add = (a) => (b) => (c) => a + b + c; console.log(add(1)(2)(3));`

6 — each call is itself a higher-order function returning the next function in the chain, closing over the argument it was just given, until the final call has all three available to add together.

Why do higher-order functions that return other functions rely on closures to be useful?

The returned function usually needs to remember something from the call that created it, like a fixed multiplier or a running cache. Without a closure over that outer scope, the returned function would have no way to access those values once the outer call finished.

What is a decorator/wrapper pattern implemented as a higher-order function?

A function that takes another function and returns a new function with extra behavior layered around it — for example, withLogging(fn) returning a function that logs the arguments and then calls fn(...args) — the original function's behavior is preserved but wrapped with logging on every call.

How does memoization work as a higher-order function?

memoize(fn) returns a new function that checks a cache (closed over between calls) for the given arguments before calling fn — if a cached result exists it's returned directly, otherwise fn runs once, its result is stored in the cache, and then returned.

Why are higher-order functions considered a core building block of functional programming?

Functional programming treats functions as regular, first-class values that can be composed, passed around, and generated dynamically — higher-order functions are exactly the mechanism that makes composing small, reusable functions into bigger behavior possible.

What's the practical difference between `return fn;` and `return fn();` inside a higher-order function?

return fn; hands back the function itself, to be called later by whoever receives it; return fn(); calls it immediately and hands back its result instead — mixing these up is a common source of 'why is this a function instead of a value' (or vice versa) bugs.

How would you build a `debounce(fn, delay)` higher-order function?

Return a new function that, on every call, clears any previously scheduled timer (stored in a variable closed over between calls) and starts a fresh setTimeout to call fn after delay — so fn only actually runs once the calls stop coming for that long.

What does it mean for JavaScript to have 'first-class functions', and why does that matter for higher-order functions?

It means functions can be stored in variables, put in data structures, passed as arguments, and returned from other functions — exactly like any other value. Higher-order functions couldn't exist at all in a language where functions were treated specially and couldn't be passed around this way.

How would you implement a `once(fn)` higher-order function that only lets `fn` run a single time?

Close over a flag (and optionally a cached result) in the returned function; on the first call, run fn, store its result, and flip the flag; every call after that skips calling fn again and just returns the stored result.

Is a callback ever itself a higher-order function?

Yes, whenever the callback being passed in itself accepts or returns a function — a callback built by greaterThan(10) is a callback in relation to filter, but it's also higher-order in its own right, since those two classifications describe independent things about it.