DEV Community

Cover image for Higher-order functions explained.
Edem Agbenyo
Edem Agbenyo

Posted on

Higher-order functions explained.

Whether you are a beginner or a 10x developer, chances are that you have used the methods of the Array Object. The methods in the Array Object are classified into two different categories. One category takes a value as arguments( string, integer, array, object) and another category takes a function as arguments.
In this article, we are going to focus on the second categories of methods called, higher-order functions and look at their implementation.
Before we dive into what higher-order functions are and what we can do with them, let's look at the reasons why we need functions in general.

Why functions?

We all agree that a program that is large in size is easily error-prone and the error is difficult to detect, hence reducing the size of the program without altering the way it works will be the ideal solution. Using functions make a program more likely to contain a bug. For example, the following code is intended to filter an array to get all the values lower than a specified predicate.

let arr= [23, 43, 12, 43, 54, 34];
let result = [];
for (let i = 0; i < arr.length; i++) {
    if (arr[i] < 40) {
      result.push(arr[i])
    }
  }
console.log(result)
Enter fullscreen mode Exit fullscreen mode

However the same could be achieved with a higher-order function using just one line of code.

console.log([23,43,12,43,54,34].filter(i=>i<40))
Enter fullscreen mode Exit fullscreen mode

Don't get me wrong, the filter method on the array object may be larger in size than our implementation but that's the goal of a function, to provide us with an abstraction.
Function, allows solutions to be expressed in the vocabulary that corresponds to the problem being solved and are reusable, therefore, prevent repetitive code.

What are higher-order functions?

In his book eloquent javascript, author Marijn Haverbeke defines higher-order functions as "Functions that operate on other functions, either by taking them as arguments or by returning them". An example is the map method on the array object.

What can we do with Higher-order functions?

Higher-order functions allow us to abstract not only values but also actions. Higher-order functions can be used to create a new function. For example:

function lowerThan(i) {
  return j => j < i;
}
let lowerThan10 = lowerThan(10);
console.log(lowerThan10(9));
Enter fullscreen mode Exit fullscreen mode

Higher-order functions can be used to change other functions or provide a new type of control. The possibilities of what one can do with higher-order functions are immense.

Implementing higher-order functions

Javascript, as a language, provides a ton of methods under the array object that are higher-functions to perform operations on arrays. Some of those functions are filter, map, reduce among others. They receive a function as an argument and return a result based on the result of the function's evaluation. Let's try to understand how these functions work under the hood.

Filter

The filter function receives a function as its argument, and that function is used to evaluate whether an element is fit to be part of the filtered result or not. Here is an example of implementation:

function filter(array, predicate) {
  let passed = [];
  for (let el of array) {
    if (predicate(el)) {
      passed.push(el);
} }
  return passed;
}
Enter fullscreen mode Exit fullscreen mode

The function receives two arguments, the array to filter and the predicate. The predicate is acting as the judge here, deciding which value to return as part of the final array. The predicate does not delete element from the array but pushes the result of the evaluation in a new array. The filter function here is an example of pure functions.

Map

A map function creates a new array out of the original array and applies the result of a function to it. The map function doesn't change the original array but maps the content to a new array. Here is an implementation of the map function.

function map(array, transform) {
   let mapped = [];
   for (let element of array) {
     mapped.push(transform(element));
   }
   return mapped;
 }
Enter fullscreen mode Exit fullscreen mode

Reduce

The reduce function is somehow, more flexible than all other higher-order functions. Reduce function can be used to perform various operations, such as summing up numbers from a collection, finding the word with the most characters in an array or flattening a multidimensional array. The reduce function operates by taking each element from the array and combining them with the current value. Ideally, you need to start each operation with a start value. Here is an implementation of the reduce function.

function reduce(array, combine, start) {
   let current = start;
   for (let element of array) {
     current = combine(current, element);
   }
   return current;
 }
Enter fullscreen mode Exit fullscreen mode

One area where higher-order functions are really useful is in function composition. In instances where you need the result of the function to be used in another function, higher-order functions provide a way to return a function as result and perform operations on them. This article is a good place to learn about composition.

In conclusion, although the scary nature of higher-order functions, they come in really handy when performing a transformation on array elements or when we need to do function composition. We see them almost everywhere these days, and I hope I have given you a good introduction on how they work and are implemented.

Top comments (0)