Basically, a function which takes another function as an argument or returns a function is known as a higher order function.
In JavaScript, functions are treated as first-class citizens. We can treat functions as values and assign them to another variable, pass them as arguments to another function, or even return them from another function.
This ability of functions to act as first-class functions is what powers higher order functions in JavaScript.
Consider the below example:
const radius = [3,1,2,4];
const calculateArea=(radius)=>{
const output = [];
for (let i = 0; i < radius.length; i++){
output.push(Math.PI * radius[i] * radius[i]);
}
return output;
}
console.log(calculateArea(radius))
//Output:
//[28.274333882308138, 3.141592653589793, 12.566370614359172, 50.26548245743669]
The above function calculates the area and gives us the required output. In the same manner if we want to calculate circumference generally we write code as
const radius = [3,1,2,4];
const calculateCircumference=(radius)=>{
const output = [];
for (let i = 0; i < radius.length; i++){
output.push(2 * Math.PI * radius[i]);
}
return output;
}
console.log(calculateCircumference(radius))
//Output :
//[18.84955592153876, 6.283185307179586, 12.566370614359172, 25.132741228718345]
But notice that we are writing a lot of duplicate code in this approach. Both the above functions do a lot of common things.
The only difference between both functions is the logic they use to calculate area and circumference.
For the function calculateArea we used (Math.PI * radius[i] * radius[i]), where as for the function calculateCircumference we used (2 * Math.PI * radius[i]).
This is where we can benefit from using higher order functions. The main intention is to create a function to do all the common stuff we did in the above two functions and pass the logic part separately as an argument to this function. Let's see how we can implement this.
Let's make the function which does all the common stuff we performed in calculateArea and calculateCircumference functions. The code is as follows:
const radius = [3,1,2,4];
const area = (radius)=>{
return Math.PI * radius * radius;
}
const circumference = (radius)=>{
return 2 * Math.PI * radius;
}
const calculate = (radius,logic)=> {
const output = [];
for (let i = 0; i < radius.length; i++){
output.push(logic(radius[i]));
}
return output;
}
console.log(calculate(radius,area)) // Output : [28.274333882308138, 3.141592653589793, 12.566370614359172, 50.26548245743669]
console.log(calculate(radius,circunference)) // Output : [18.84955592153876, 6.283185307179586, 12.566370614359172, 25.132741228718345]
In the above example, we have created a generic function called calculate which accepts the logic and radius , we kept all the common steps, that is creating empty array , looping the array which was passed as an argument and the remaining logic which is different is a separate function and is passed to the generic function.
In this manner we reduce lot of duplicate code.
We know that JavaScript provides us with some inbuilt higher order functions like map()
, filter()
, reduce()
and so on
Lets dive deep into them:
Map function is used to transform an array. Let's take an example :
const arr = [5,1,3,2,6];
function double(x){
return x * 2;
}
function triple(x){
return x * 3;
}
function binary(x){
return x.toString(2)
}
const doubledArr = arr.map(double)
console.log(doubledArr); // Output: [10,2,6,4,12]
const trippledArr = arr.map(triple)
console.log(trippledArr); // Output: [15,3,9,6,18]
const binaryArr = arr.map(binary);
console.log(binaryArr); // Output: ["101","1","10","110"]
In the above code, we have created functions for the logic and passing as argument to map function. The map method iterates through the given array and executes the logic and gives a new array.
Filter function is basically used to filter inside an array. Lets take an example of filtering odd and even values from the given array :
const arr = [5,1,3,2,6];
function isOdd(){
return x % 2;
}
function isEven(){
return x % 2 === 0;
}
const oddNumArr = arr.filter(isOdd);
console.log(oddNumArr); // Output : [5,1,3]
const evenNumArr = arr.filter(isEven);
console.log(evenNumArr); // Output : [2,6]
In the above example , the filter method iterates through the given array and filters out odd and even values according to the logic provided.
Reduce function is employed when you have an array of elements and you want to condense it into a single value. Lets take an example of sum of numbers and lets see how we can write it in normal function to understand reduce much better, the code looks like:
const arr = [5,1,3,2,6];
function findSum(arr){
let sum = 0;
for(let i=0; i < arr.length; i++){
sum = sum + arr[i]
}
return sum;
}
console.log(findSum(arr));// Output : 17
In the above code, a for loop is run , iterating through the elements inside the array and finding the sum of all. This same code can be written with reduce function. Lets see how we can transform this logic using reduce function,
const arr = [5,1,3,2,6];
const output = arr.reduce(function(acc,curr){
acc = acc + curr[i];
return acc;
},0);
console.log(output); // Output :17
The reduce
function needs two things: a function that works with two parameters, "acc" (short for accumulator) and "curr" (current value), and an initial value provided as "acc". It goes through each element of an array, applying the function to combine the current value with the accumulator. In the end, it gives a single value as the result, where "acc" holds the final outcome.
These are some inbuilt higher order functions provided by JavaScript.