DEV Community

John Au-Yeung
John Au-Yeung

Posted on • Originally published at thewebdev.info

What are Higher-Order Functions in JavaScript?

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

In JavaScript, higher-order functions are used in many places. Therefore, it’s important to know what they are.

In this article, we’ll look at what higher-order functions are and how to use them in JavaScript.

Definition of Higher-Order Functions

Higher-order functions are functions that take other functions as arguments or return functions as their results. A function that’s accepted as an argument is also called a callback function.

Why can functions accept other functions as arguments or return functions? This is because JavaScript functions are objects like any other entity in JavaScript. Functions that are objects are called first-class functions.

First-class functions are treated like any other variables. In JavaScript, this is the case, so JavaScript functions are first-class functions.

In JavaScript, we can assign functions to variables:

let foo = () => 1;
Enter fullscreen mode Exit fullscreen mode

In the code above, we assigned a simple anonymous function to the foo variable.

Then we can call it by running:

foo();
Enter fullscreen mode Exit fullscreen mode

We can also add properties to it as follows:

foo.bar = 1;
Enter fullscreen mode Exit fullscreen mode

The code above is bad practice because it’s confusing since functions are usually called rather than manipulated by adding properties to them.

However, we know from this that JavaScript functions are objects. It also has a prototype with methods like apply, bind, and call to modify the behavior of regular functions declared with the function keyword.

Everything that we want to do with other variables like numbers, strings, and objects, we can do with functions.

Functions as Function Parameters

Because JavaScript functions are just regular objects, we can pass them in as arguments when we call a function. This is used in many places like array functions and promise callbacks.

A simple example would be the following:

const addOrMultiply = (addFn, multiplyFn, a, b) => {  
  if (Math.random() > 0.5) {  
    return addFn(a, b);  
  }  
  return multiplyFn(a, b);  
}

const add = (a, b) => a + b;  
const multiply = (a, b) => a * b;  
const result = addOrMultiply(add, multiply, 1, 2);
Enter fullscreen mode Exit fullscreen mode

In the code above, we defined the addOrMultiply function which takes a function to add 2 numbers, function to multiply 2 numbers, and 2 numbers as arguments.

In the function, if Math.random() returns a number bigger than 0.5, then we call addFn(a, b) . Otherwise, we call multiplyFn(a, b) .

Then we defined the add and multiply functions to add and multiply 2 numbers respectively.

Finally, we call the addOrMultiply function by passing inadd and multiply functions and numbers 1 and 2.

This way, the functions we pass in get called with a and b . This doesn’t mean that the function we pass in have to match the signature of the function calls inside the addOrMultiply function. JavaScript doesn’t care about the signatures of the function we pass in. However, we’ve to pass in functions that get us the expected results.

By the definition that we mentioned for higher-order function, addOrMultiply fits the definition of it.

Examples of Higher-Order Functions

Array.prototype.forEach

We can use the forEach method to loop through each element of an array. It takes a callback function as an argument. The callback takes the array entry currently being processed, index of the array being processed, and the array itself as the parameter.

The index and the array parameters are optional. However, we know that JavaScript doesn’t care about the function signature of functions we use for callbacks, so we’ve to be careful.

We can write the following code:

const arr = [1, 2, 3];  
arr.forEach((a, i) => console.log(`arr[${i}] is ${a}`))
Enter fullscreen mode Exit fullscreen mode

We should see:

arr[0] is 1  
arr[1] is 2  
arr[2] is 3
Enter fullscreen mode Exit fullscreen mode

logged from the console.log .

Array.prototype.map

The map array method takes the same callback function as forEach . It’s used for mapping array entries of the array it’s called on to values returned by manipulating each entry with the callback function. It returns a new array.

For example, we can use is as follows:

const arr = [1, 2, 3];  
arr.map((a, i) => a**2)
Enter fullscreen mode Exit fullscreen mode

Then we should get:

[1, 4, 9]
Enter fullscreen mode Exit fullscreen mode

setTimeout

The setTimeout function delays the execution of the code inside the callback function that we pass into it by a specified amount of time.

For example, we can use it as follows:

setTimeout(() => {  
  console.log('hi');  
}, 1000)
Enter fullscreen mode Exit fullscreen mode

The code above will log 'hi' 1 second after the setTimeout function is called.

setTimeout defers the code inside the callback to the next event loop iteration so that we delay the execution of the code in the callback without holding up the whole program.

This kind of delayed code is asynchronous. We delay code execution without holding up the main execution thread to wait for its execution to finish.

This pattern is common to lots of asynchronous code, including callbacks for promises, event listeners and other pieces of asynchronous code.

Since we can’t execute asynchronous code line by line, callbacks are even more important since it’s the only way to run a function in an indeterminate amount of time.

Event Handlers

Event handlers for DOM elements and in Node.js also use callbacks since there’s code that is only called when an event is triggered.

For example, we can attach a simple click listener to the document object as follows:

document.addEventListener('click', () => {  
  console.log('clicked');  
})
Enter fullscreen mode Exit fullscreen mode

Then whenever we click on the page, we’ll get 'clicked' logged.

As we can see higher-order functions are very useful in JavaScript. It lets us create callback functions to pass into other functions. It’s widely used by synchronous code and asynchronous code alike.

Synchronous callbacks examples include callbacks that we pass into array methods.

Asynchronous callbacks include event handlers, setTimeout , promise callbacks and more. It’s widely used with asynchronous code since the code isn’t run line by line, so we need callbacks to run code that needs to be run in an indeterminate amount of time.

Top comments (0)