Higher-order functions are functions that make use of functions as either their argument or their return value. They are an important feature that cannot be overlooked in functional programming, allowing for easy nesting of functions to archive a specific task.
Today, we will be looking into what higher-order functions are in JavaScript, their importance and their role in functional programming. JavaScript is suitably known for functional programming because it accepts higher-order functions, which have been used extensively in the language.
To easily understand this topic, we need to understand better what functions and functional programming are.
Functions are “self-contained” modules of code that accomplish a specific task.
Functions usually “take in” data, process it and “return” a result. Once a function is created, it can be reused multiple times. Let’s quickly take a look at an example before we continue.
//Declaring the Function
function greetings() {
return "Good Morning"
}
//Executing the Function
greetings()
greetings()
The code snippet above shows that lines 2 to 4 contain the declaration of the function, while line 6 contains the execution. Once they are written, the exciting thing about functions is that they can be executed multiple times, making your code more compact and less repetitive, hence earning the acronym DRY (Don’t Repeat Yourself).
“Functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data.” – Wikipedia
There are many patterns used by developers while coding, and functional programming is one of them. Some other examples include object-oriented programming, procedural programming, etc.
Since the adoption of functional programming in JavaScript, many large codebase applications have been using the approach to create a cleaner codebase and avoid redundancy.
Functional programming has also created an accessible environment for open-source programming. It allows developers to write the code based on the task given and structure it in a functional approach, simplified to be readable even for beginners.
“Functions are first-class citizens in JavaScript” is a popular expression used by many developers because functions in JavaScript are a special type of object. Let’s take an example.
function favouriteFood(){
return "rice";
}
//Execute function
favouriteFood()
//returns rice
//Added Properties to the function
favouriteFood.beans = "Beans"
console.log(favouriteFood.beans)
//prints Beans
From the code above, we understand that a property is added to the function after it has been declared, and it returns the property value anytime the property is invoked.
Note: Passing property to a function may be valid but cannot be verified as a good practice.
Higher-order functions are functions that make use of functions as either their argument or their return value. Using functions in both roles is unnecessary; if a function works with either of the two, it becomes a higher-order function.
In JavaScript functions, map, filter and reduce are examples of built-in higher-order functions. Let’s look more closely at these three.
A map()
function creates a new array populated with results by calling a callback function provided as an argument. It takes every return value from the callback and stores them in a new array.
The callback function to pass to the map()
function accepts three arguments:
For example, we have an array of numbers, and we want to create a new array that will contain every element in the first array multiplied by ten. Let’s solve the problem with and without a higher-order function.
Using a Normal Function
Here’s how we can solve the problem using a normal function.
const num = [10, 20, 30];
const num10 = [];
for(let i = 0; i < num.length; i++) {
num10.push(num[i] * 2);
}
// prints [ 100, 200, 300 ]
console.log(num10);
Using a Higher-Order Function (Map)
With a higher-order function, the code is shorter; here’s the code below.
const num = [10, 20, 30];
const num10 = num.map(i => i * 2);
console.log(num10);
From the above map function, you can see that we can achieve the same output with less code and better structure. So, let us move to the next built-in function.
The filter() function creates a new array populated with all the elements that passed the condition of the callback function; just like the map function, the filter function also accepts three arguments: an element, an index and an array.
For example, let’s say we have an array containing objects with students offering a course and the status if they attended the class or not, and we need to filter the array to get all students that attended.
Using a Normal Function
Here’s how we can solve the problem using a normal function.
const students = [
{ name: 'John James', status: true},
{ name: 'Micheal Obi', status: false },
{ name: 'Bola Ade', status: true },
{ name: 'Emmanuel', status: false },
{ name: 'Faithfulness Alamu',status: true },
];
const presentStudent= [];
for(let i = 0; i < student.length; i++) {
if(students[i].status >= true) {
presentStudent.push(students[i].name);
}
}
console.log(presentStudent);
//Output
//[ 'John James', 'Bola Ade', 'Faithfulness Alamu' ]
Using a Higher-Order Function (Filter)
Here’s the same problem solved using a higher-order function.
const students = [
{ name: 'John James', status: true},
{ name: 'Micheal Obi', status: false },
{ name: 'Bola Ade', status: true },
{ name: 'Emmanuel', status: false },
{ name: 'Faithfulness Alamu', status: true },
];
const presentStudent =students.filter(student => student.status == true);
console.log(presentStudent);
This method executes a callback function on every element in the array, which results in a single value. The method accepts two arguments:
The callback function accepts the following four parameters:
Here’s an example, where we add up all the elements in an array.
Using a Normal Function
Here’s how we can solve the problem using a normal function.
const numbers = [10, 29, 11, 43, 37];
let subtract = 0;
for(let i = 0; i < arr.length; i++) {
subtract = subtract + numbers[i];
}
console.log(subtract); // prints 110
Using a Higher-Order Function (Reduce)
The same problem was solved using a higher-order function.
const numbers = [10, 29, 11, 43, 37];
const subtract = numbers.reduce(function(acc, value) {
return acc + value;
});
console.log(subtract); // prints 110
From all the examples above, you can see that higher-order functions make the code cleaner and easier to comprehend.
So far, I have only shown examples of higher-order functions from the built-in functions in JavaScript; now, let’s dive into creating our own.
We will be creating a clone of the map function. For example, we have an array containing names; we want to get the length of each name using the higher-order function we will create.
function mapClone(arr, fn) {
const nameList = [];
for(let i = 0; i < arr.length; i++) {
nameList.push(
fn(arr[i])
);
}
return nameList;
}
...
In the above code, mapClone
takes in an array and a function fn
, which is the callback. Next, we created an empty array called nameList
, that will contain the final result. The loop iterates over the given
array and calls the callback function on every element, after which it returns the nameList
array.
const names = ['Emmanuel', 'John', 'Philip', 'James', 'Andrew'];
const nameLength = mapClone(names, function(item) {
return item.length;
});
console.log(nameLength) // prints [ 8, 4, 6, 5, 6 ]
Run the code above to test the higher-order function we just created.
In summary, we learned the concept behind the higher-order function and how to use it effectively. We also created a higher-order function from scratch to understand the inner workings, not just the implementation.
Chinedu is a tech enthusiast focused on full-stack JavaScript and Infrastructure engineering.