Higher Order Functions are functions that take other functions as arguments or return functions as their results. The idea of Higher Order Functions is borrowed from functional programming, and it allows JavaScript to be more expressive and concise.
Higher Order Functions are a powerful tool in the hands of developers, as they can use them to create complex functions that are easy to read and maintain. They provide a way to abstract common patterns in code and create reusable code blocks. Higher Order Functions can be used for many different tasks such as filtering, mapping, and reducing arrays, currying functions, and composing functions.
In this article, we will explore Higher Order Functions in JavaScript in detail, and provide examples of how to use them.
What are Higher Order Functions?
Higher Order Functions are functions that take other functions as arguments or return functions as their results. They are called higher-order because they operate on other functions.
Higher Order Functions are a key feature of functional programming, which emphasizes the use of functions as building blocks for solving problems. In functional programming, functions are treated as first-class citizens, meaning they can be passed around just like any other value.
JavaScript supports Higher Order Functions natively, allowing developers to create complex and flexible functions with ease. Higher Order Functions can be used to create abstractions that encapsulate common patterns in code, such as filtering, mapping, and reducing arrays.
Higher Order Functions in Action
Let’s look at some examples of Higher Order Functions in JavaScript.
- Filter
The filter method is a Higher Order Function that takes a callback function and returns a new array containing only the elements that pass a test specified by the callback function. Here’s an example:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter((number) => {
return number % 2 === 0;
});
console.log(evenNumbers); // Output: [2, 4]
In this example, the filter method takes a callback function that tests whether a number is even or odd. The filter method then returns a new array containing only the even numbers.
- Map
The map method is a Higher Order Function that takes a callback function and returns a new array containing the results of applying the callback function to each element in the original array. Here’s an example:
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map((number) => {
return number ** 2;
});
console.log(squaredNumbers); // Output: [1, 4, 9, 16, 25]
In this example, the map method takes a callback function that squares each number in the original array. The map method then returns a new array containing the squared numbers.
- Reduce
The reduce method is a Higher Order Function that takes a callback function and an optional initial value and returns a single value by reducing the original array. Here’s an example:
const numbers = [1, 2, 3, 4, 5];
const sumOfNumbers = numbers.reduce((accumulator, number) => {
return accumulator + number;
});
console.log(sumOfNumbers); // Output: 15
In this example, the reduce method takes a callback function that adds each number in the original array to an accumulator. The reduce method then returns the sum of all the numbers in the original array.
- Currying
Currying is the process of transforming a function that takes multiple arguments into a function that takes one argument at a time. This allows you to create a new function by partially applying the arguments to the original function.
Here’s an example of a curried function that takes two arguments:
function add(a, b) {
return a + b;
}
const curriedAdd = (a) => (b) => a + b;
console.log(add(1, 2)); // 3
console.log(curriedAdd(1)(2)); // 3
By currying the add function, we can create a new function that only takes one argument at a time. This can be useful when you want to create a new function with some of the arguments pre-set.
5. bind()
The bind()
method is a higher order function that allows you to create a new function that has a predefined this
value and any number of arguments that you specify.
const person = {
firstName: "John",
lastName: "Doe",
getFullName: function() {
return this.firstName + " " + this.lastName;
}
};
const greet = function(greeting) {
console.log(greeting + ", " + this.getFullName());
};
const boundGreet = greet.bind(person, "Hello");
boundGreet(); // "Hello, John Doe"
6. Callback Functions
A callback function is a function that is passed as an argument to another function and is executed when the first function is called. This is a common pattern in JavaScript and is used for event handling, asynchronous programming, and other purposes.
const getUserData = function(callback) {
setTimeout(() => {
const userData = { name: "John Doe", age: 30 };
callback(userData);
}, 1000);
};
getUserData((userData) => {
console.log(userData); // { name: "John Doe", age: 30 }
});
In an advanced javascript interview, interviewer generally asks you to make prototype of map, reduce, filter. so please go through below code to understand how they are written.
Q: How to write prototype of map ?
example of a prototype function of map
in JavaScript:
Array.prototype.myMap = function(callback) {
const newArray = [];
for (let i = 0; i < this.length; i++) {
newArray.push(callback(this[i], i, this));
}
return newArray;
};
This function is added to the prototype of the Array
object so that any array can use it by calling myMap
method. It takes a callback
function as an argument, which will be called on each element of the array. The callback function will be passed three arguments: the current element, the index of the current element, and the array itself.
The function creates a new array newArray
and pushes the return value of the callback function for each element into it. Finally, it returns the new array with the mapped values.
Here is an example of how to use this myMap
function:
const arr = [1, 2, 3];
const newArr = arr.myMap(function(item) {
return item * 2;
});
console.log(newArr); // [2, 4, 6]
In this example, we call myMap
on the array [1, 2, 3]
and pass a callback function that multiplies each element by 2. The myMap
function then returns a new array [2, 4, 6]
with the mapped values.
Q: How to write prototype of filter ?
here is the example of a prototype function for filter
in JavaScript:
Array.prototype.myFilter = function(callback) {
let filteredArr = [];
for(let i = 0; i < this.length; i++) {
if(callback(this[i], i, this)) {
filteredArr.push(this[i]);
}
}
return filteredArr;
}
This function extends the Array
object with a new method called myFilter
. It takes a callback function as an argument and returns a new array containing only the elements of the original array for which the callback function returns true
.
The callback
function passed to myFilter
takes three arguments: the current element being processed, its index, and the array on which myFilter
was called. In this example, the for
loop iterates through each element of the array and checks whether the callback function returns true
for that element. If so, it adds the element to a new array called filteredArr
. Finally, the function returns filteredArr
.
Here’s an example of using myFilter
to get all the even numbers from an array:
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.myFilter((num) => {
return num % 2 === 0;
});
console.log(evenNumbers); // [2, 4, 6, 8, 10]
Note that this implementation of filter
is similar to the built-in filter
method in JavaScript, but with a different name and some differences in the handling of the callback function.
Q: How to write prototype of reducer ?
Here’s an example of how to create a prototype function of reduce
in JavaScript:
Array.prototype.myReduce = function(callback, initialValue) {
let accumulator = initialValue === undefined ? undefined : initialValue;
for(let i = 0; i < this.length; i++) {
if(accumulator !== undefined) {
accumulator = callback.call(undefined, accumulator, this[i], i, this);
} else {
accumulator = this[i];
}
}
return accumulator;
};
In this code, we are extending the Array
prototype to add a new function called myReduce
. The myReduce
function takes two arguments: a callback
function and an optional initialValue
.
The myReduce
function works by iterating over each element of the array and applying the callback
function to the current element and an accumulator. The accumulator
variable keeps track of the accumulated result of each iteration. The callback
function takes four arguments: the accumulator, the current element, the current index, and the original array.
If an initialValue
is provided, then the accumulator
is set to that value before the first iteration. Otherwise, the accumulator
is set to the first element of the array.
Finally, the myReduce
function returns the final value of the accumulator
after all iterations are completed.
Here’s an example of how to use the myReduce
function:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.myReduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // Output: 15
In this example, we are using the myReduce
function to calculate the sum of all the elements in the numbers
array. The callback
function takes two arguments: the accumulator and the current element. The initialValue
is set to 0
so that the first iteration starts with the accumulator at 0
. The final result is 15
, which is the sum of all the elements in the array.
Q: Write prototype of bind
Here is the prototype function of bind()
:
Function.prototype.bind = function(thisArg, ...args) {
const fn = this;
return function(...innerArgs) {
return fn.apply(thisArg, [...args, ...innerArgs]);
};
};
In this prototype function, we first store the function that bind()
is called on in a variable fn
. We then return a new function that, when called, will execute the original function with the this
keyword set to thisArg
, which is the first argument passed to bind()
. We also concatenate any additional arguments passed to bind()
with the arguments passed to the new function, using the apply()
method.
This is a simplified version of the bind()
function, but it demonstrates the basic concept of how the bind()
method works.