What makes Javascript suitable for functional programming is that it accepts Higher-Order Functions. Higher-Order Functions are extensively used in Javascript.
What is Higher-Order Function?
A higher-order function is a function that receives a function as an argument or returns the function as an output.
Taking other functions as arguments is often referred to as a callback
function because it is called back by the higher-order function. This is a concept that Javascript uses a lot.
For example, .map()
, .filter()
, .reduce()
etc. are some built-in higher-order functions.
So let’s discuss some of the useful built-in higher-order functions in Javascript.
.map()
Let’s look at this array method with a simple example. Say you have received an array containing multiple objects — each one representing a person. The thing you need in the end is an array containing only the names of each person.
1// You have:
2const persons = [
3{id: 1, name: 'John'},
4{id: 2, name: 'Bob'},
5{id: 3, name: 'Adam'}
6];
7// What you need:
8['John', 'Bob', 'Adam'];
There are multiple ways to achieve this. You might want to do it by creating an empty array and then using .forEach()
, for(…of)
, or simply for()
to meet your goal.
But now let’s see with a .map()
method.
1const personsName = persons.map(person => person.name);
How does .map() work?
It takes two arguments, a callback, and an optional context (will be considered as ‘this’
in the callback). The callback runs for each value in the array and returns each new value in the resulting array.
1Note: the resulting array will always be the same length as the original array.
.reduce()
Just like .map()
, reduce also runs a callback for each element of an array. What’s different here is that reduce passes the result of this callback (the accumulator ) from one array element to the other.
The accumulator can be anything such as integer, string, object, array, etc… and must be instantiated or passes when calling .reduce().
Let’s look at an example.
1const players= [
2 {id: 10, name: 'John', points: 57},
3 {id: 11, name: 'Kyle', points: 52},
4 {id: 12, name: 'Bob', points: 63}
5];
We need to know the total points of all of them. With .reduce()
, it’s pretty straight-forward.
1const totalPoints = players.reduce((accumulator, person) => {
2 return accumulator + person.points;
3}, 0); //172
After running the callback for each element of the array, reduce will return the final value of our accumulator (in our case ‘0’).
Now let’s say I want to find which player has the highest points. For that, I can also use it as well.
1const highestPlayer = players.reduce((lowest, player) => {
2 return (lowest.points || 0) > player.points ? lowest : player
3}, {});
I named my accumulator ‘lowest’. My callback compares the accumulator to each player. If a player has more points than the lowest, then the player becomes the new lowest. So that is the one I return.
So, using .reduce()
is an easy way to generate a single value of object from an array.
.filter()
What if you have an array, but only want some of the elements in it? That's where .filter() comes in!
Here’s our data:
1const persons = [
2 {id: 1, name: 'John', profession: 'Engineer'},
3 {id: 2, name: 'Bob', profession: 'Developer'},
4 {id: 3, name: 'Rocky', profession: 'Singer'},
5 {id: 4, name: 'Kyle', profession: 'Developer'}
6];
7
Say, we want an array of people having the profession of ‘Developer’ only. With .filter()
, it could be a lot easier.
1const developer = persons.filter(person => {
2 return person.profession === 'Developer';
3});
Basically, if the callback function returns true, the current element will be in the resulting array. If it returns false, it won't be.
.some()
This array method helps you determine if one or more of its values correspond to something you’re looking for.
Let’s illustrate with an example. Here is a list of random numbers in an array.
1const numbers = [1, 2, 3, 4, -1, -2, 5];
You want to know if there are any negative numbers. There are many ways to achieve that goal. But .some()
might be an easy way.
1const hasNegativeNumbers = numbers.some(number => number < 0); //true
How does it work?
Well, you pass .some()
a function as an argument. That function runs for each value in the array. You can then see if the value fits the condition you’ve written. The function must return a boolean (although a truthy/falsy) value works as well. As soon as one true is returned, .some()
will itself return true. If none of the values when processed in your condition returns true(if they all return false) then .some() will return false
.
Note: As soon as a single true is returned, .some()
will stop checking the other array values.
.every()
This array method works similarly to the .some()
but it checks if every element or values passes a particular test.
Let's illustrate with an example.
1const numbers = [1, 2, 3, 5, 6, 11, 23, 45];
You want to know that all the numbers are greater than 0, then with .every()
it’s pretty straight-forward.
1const allPositiveNumbers = numbers.every(number => number > 0); //true
It will check each and every element in an array and return true if all values meet the criteria, and false if not.
.find()
This array method does exactly what it says. It finds what you’re looking for. The .find() will return the first value that corresponds to the passed condition. Let’s see with an example.
Here is our list of persons.
1const persons = [
2 {id: 1, name: 'Ricky', developer: false},
3 {id: 2, name: 'Jack', developer: true},
4 {id: 25, name: 'Chris', developer: false}
5];
If we want an object that has a ‘developer ’ property to be true, we can output the value by using .find().
1const developer = persons.find(person => person.developer);
Note: if it doesn’t find then it will return undefined
.
What is the difference between .filter()
and .find()
?
.find()
will return to the first match. If more values match your condition then it won’t matter. Only the first match will be returned. If you need a list of all matched then you can use .filter()
instead of .find()
.
Conclusion:
These are the few commonly used built-in higher-order functions. A higher-order function is a function that may receive a function as an argument and can even return a function.
Higher-order functions are just like regular functions with the added ability to receive and return other functions as arguments and outputs.