Higher-order Functions
Greetings, friends! Have you ever been asked what a "higher-order function" is during an interview? It sounds complicated, but it's actually really simple. According to Wikipedia, a higher-order function is a function that does at least one of the following:
- Takes one or more functions as arguments
- Returns a function as its result
You may have seen examples of higher-order functions already. When we create functions that accept a callback function, it fulfills the first criterion of being a higher-order function.
function higherOrderFunction(callback) {
callback();
}
function logInfo() {
console.log('logging info...')
}
higherOrderFunction(logInfo);
// OUTPUT: logging info...
In my personal experience, it's more common to refer to functions as higher-order functions when the second criterion is fulfilled. That is, the function returns a function as its result. Let's look at an example.
function multiplyBy(multiple) {
return function multiplyValues(num) {
return multiple * num;
}
}
const double = multiplyBy(2);
const finalResult = double(3);
console.log(finalResult);
// OUTPUT: 6
In the code snippet above, we are creating a function called multiplyBy
that returns another function. The inner function will then return the product of multiple
and num
.
We assign the result of multiplyBy(2)
to the variable, double
. This variable is now equal to the inner function but with multiple
set to 2
. Think of double
being equal to the following:
const double = function multiplyValues(num) {
return 2 * num;
}
Next, we assign double(3)
to the variable, finalResult
. This variable is now equal to the product of multiple
and sum
. Think of finalResult
being equal to the following:
const finalResult = multiplyValues(3) // return 2 * 3 = 6
When we log finalResult
to the console, we obtain the product of 2 * 3
which equals 6
. Do you see what happened? We assigned a function to a variable. Then, we deferred execution of our function until later. This pattern is very common in JavaScript.
Let's take a look at our example using arrow functions instead.
const multiplyBy = multiple => {
return (num) => {
return multiple * num;
}
}
const double = multiplyBy(2);
const finalResult = double(3);
console.log(finalResult);
// OUTPUT: 6
If we use a concise body for the arrow function, we can make the code even shorter.
const multiplyBy = multiple => num => multiple * num;
const double = multiplyBy(2);
const finalResult = double(3);
console.log(finalResult) // 6
But wait! There's more! If we remove the two variables, we can make this code even shorter!
const multiplyBy = multiple => num => multiple * num;
console.log(multiplyBy(2)(3)) // 6
Our code is tremendously cleaner now! Additionally, we can also create new functions out of our higher-order functions.
const multiplyBy = multiple => num => multiple * num;
const double = multiplyBy(2);
const triple = multiplyBy(3);
const quadruple = multiplyBy(4);
console.log(double(3)) // 6
console.log(triple(3)) // 9
console.log(quadruple(3)) // 12
I hope you see the power of higher-order functions now! Next time you're asked about them during an interview, I'm sure you'll be ready 🙂.