Logo

DevPro

Practice Questions

What is the definition of a higher-order function in JavaScript?

TL;DR

A higher-order function is any function that takes one or more functions as arguments, which it uses to operate on some data, and/or returns a function as a result.

Higher-order functions are meant to abstract some operation that is performed repeatedly. The classic example of this is Array.prototype.map(), which takes an array and a function as arguments. Array.prototype.map() then uses this function to transform each item in the array, returning a new array with the transformed data. Other popular examples in JavaScript are Array.prototype.forEach(), Array.prototype.filter(), and Array.prototype.reduce(). A higher-order function doesn't just need to be manipulating arrays as there are many use cases for returning a function from another function. Function.prototype.bind() is an example that returns another function.

Imagine a scenario where we have an array of names that we need to transform to uppercase.

const names = ['irish', 'daisy', 'anna'];

The imperative way will be as such:

function transformNamesToUppercase(names) {
  const results = [];
  for (let i = 0; i < names.length; i++) {
    results.push(names[i].toUpperCase());
  }
  return results;
}

transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

Using Array.prototype.map(transformerFn) makes the code shorter and more declarative.

function transformNamesToUppercase(names) {
  return names.map((name) => name.toUpperCase());
}

transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']

Higher order functions

A higher-order function is a function that takes another function as an argument or returns a function as its result.

Functions as arguments

A higher-order function can take another function as an argument and execute it.

function greet(name) {
  return `Hello, ${name}!`;
}

function greetName(greeter, name) {
  console.log(greeter(name));
}

greetName(greet, 'Alice'); // Output: Hello, Alice!

In this example, the greetName function takes another function greet as an argument and executes it with the name Alice. The greet function is a higher-order function because it is passed as an argument to another function.

Functions as return values

A higher-order function can return another function.

function multiplier(factor) {
  return function (num) {
    return num * factor;
  };
}

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

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

In this example, the multiplier function returns a new function that multiplies any number by the specified factor. The returned function is a closure that remembers the factor value from the outer function. The multiplier function is a higher-order function because it returns another function.

Practical examples

  1. Logging decorator: A higher-order function that adds logging functionality to another function:
function withLogging(fn) {
  return function (...args) {
    console.log(`Calling ${fn.name} with arguments`, args);
    return fn.apply(this, args);
  };
}

function add(a, b) {
  return a + b;
}

const loggedAdd = withLogging(add);
console.log(loggedAdd(2, 3)); // Output: Calling add with arguments [2, 3] 5

The withLogging function is a higher-order function that takes a function fn as an argument and returns a new function that logs the function call before executing the original function

  1. Memoization: A higher-order function that caches the results of a function to avoid redundant computations:
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;
  };
}

function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // Output: 55

The memoize function is a higher-order function that takes a function fn as an argument and returns a new function that caches the results of the original function based on its arguments.

  1. Lodash: Lodash is a utility library that provides a wide range of functions for working with arrays, objects, strings, and more, most of which are higher-order functions.
import _ from 'lodash';

const numbers = [1, 2, 3, 4, 5];

// Filter array
const evenNumbers = _.filter(numbers, (n) => n % 2 === 0); // [2, 4]

// Map array
const doubledNumbers = _.map(numbers, (n) => n * 2); // [2, 4, 6, 8, 10]

// Find the maximum value
const maxValue = _.max(numbers); // 5

// Sum all values
const sum = _.sum(numbers); // 15

Further reading

162 / 193