CodingNic

Functions

Higher-Order Functions

Functions 15 min read

Higher-Order Functions

Objectives

By the end of this chapter, you should be able to:

  • Explain what a higher-order function is
  • Write a function that takes another function as an argument and calls it
  • Write a function that returns a new function
  • Explain how a returned function connects back to closures

💡 Why this matters: In JavaScript, functions can be passed around just like numbers or strings: stored in variables, passed as arguments, returned from other functions. Once that clicks, a huge amount of JavaScript code (including the array methods you’ll meet next module) becomes far easier to read.

What Is a Higher-Order Function?

A higher-order function is a function that does at least one of these two things:

  • takes another function as an argument, or
  • returns a function.

In JavaScript, functions are values, so they can be passed into other functions and returned out of them, exactly like a number or a string could be.

Taking a Function as an Argument

Here’s a function repeat that calls whatever function it’s given, n times:

javascript
function repeat(n, fn) {
  for (let i = 1; i <= n; i++) {
    fn(i);
  }
}

repeat(3, function (i) {
  console.log("Rep " + i);
});
// Rep 1
// Rep 2
// Rep 3

repeat doesn’t know or care what fn actually does. It just calls it, three times, passing each call the current count. That’s what makes repeat reusable: pass it a different function, get completely different behavior, with no changes to repeat itself.

You can also pass in a function that already has a name, instead of writing one inline:

javascript
function sayHello(name) {
  console.log("Hello, " + name);
}

function callTwice(fn, value) {
  fn(value);
  fn(value);
}

callTwice(sayHello, "Maya");
// Hello, Maya
// Hello, Maya

Notice sayHello is passed without parentheses, sayHello, not sayHello(). Writing sayHello() would call it immediately and pass its return value instead. Passing sayHello hands callTwice the function itself, to call whenever it wants.

Returning a Function

A higher-order function can also build and return a new function. This is where higher-order functions connect directly to closures from the last lesson.

javascript
function makeMultiplier(factor) {
  return function (n) {
    return n * factor;
  };
}

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

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

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

makeMultiplier returns a function, which makes makeMultiplier itself a higher-order function. But look closer at what it returns: a function that remembers factor from where it was created. That’s a closure, exactly like makeCounter in the previous lesson. double and triple are two separate closures, each remembering its own factor, which is why they behave differently even though they were built from the same code.

Try It

  1. Write a higher-order function applyTwice(fn, value) that calls fn on value, then calls fn again on the result of that first call, returning the final result. Write a small function addFive(n) that returns n + 5. Call applyTwice(addFive, 10) and log the result.
  2. Write a higher-order function makeAdder(x) that returns a function which adds x to whatever number it’s called with. Create add10 = makeAdder(10), then call add10(5) and log the result.
  3. Using makeAdder from the exercise above, create a second adder, add100, and confirm it behaves independently of add10 by calling both and logging both results.

Recap

  • A higher-order function either takes a function as an argument, returns a function, or both.
  • Passing a function as an argument (without calling it) lets the receiving function decide when and how to call it.
  • A function that returns another function is, in effect, returning a closure, one that remembers the variables from where it was built.

You’ll meet this pattern constantly starting next module: the built-in array methods .map(), .filter(), and .reduce() are all higher-order functions, each one takes a function as its argument, exactly like repeat() did here. Next lesson: exercises to practice everything from this module.