By definition, an higher order function is a function which, at least, receives one or more other functions as arguments or returns another function as its result. In this tutorial we will focus on standard library functions as filter, map and reduce: we will see when they can be useful and how to use them.
In this tutorial you will learn:
- What is an higher order function.
- Why we can use higher order functions in Javascript.
- How and when to use filter, map and reduce functions.
Category | Requirements, Conventions or Software Version Used |
---|---|
System | Operating system agnostic. |
Software | An installation of node to follow this tutorial in a non-browser environment. |
Other | Knowledge of Javascript and object oriented concepts. |
Conventions | # – requires given linux commands to be executed with root privileges either directly as a root user or by use of sudo command$ – requires given linux commands to be executed as a regular non-privileged user |
What is an higher order function ?
In Javascript functions are first class objects
: they can be assigned to variables, passed as arguments to other functions, or be returned by other functions. The use of higher order functions is based on this peculiarities. We define an higher order function as a function which at least accepts other functions as its arguments, or returns another function as its result. In this tutorial we will focus on standard library functions as filter
, map
and reduce
.
In this tutorial, we will make a use of arrow functions
: if you want to know more about this new function syntax, you could check this tutorial we published on the subject.
Filter or array.prototype.filter
The first function we will talk about is filter
, or, to use its complete name, array.prototype.filter
. This function is actually a method of the array
object, and what it does it’s very simple: it returns a new array composed by the elements of the original array which pass the test implemented in its body.
To be clear, let’s see an example. Suppose we have an array of words and we want to “filter” words composed by exactly three letters. We could obtain what we want by using a for
loop, writing:
const words = ["house", "pen", "book", "computer", "car"];
const shortWords = [];
// We could use a standard c-style for loop...
for (let i = 0; i < words.length; i++) {
if (words[i].length == 3) {
shortWords.push(words[i])
}
}
//... or a for...of loop
for (let word of words) {
if (word.length == 3) {
shortWords.push(word);
}
}
Both the examples above work, and the with both we achieve the same result. After the code is executed, the “shortWords” array will have two members: “pen” and “car”. You may notice, however, that especially the first example is pretty verbose. Let’s see how we can accomplish the same result with less code, by using filter
:
const shortWords = words.filter((element) => element.length == 3);
We obtained the exact same result. There is, however, one difference: this time, by also using an arrow
function, we wrote all in just one line of code!. Here is how filter
works: it accepts only one “mandatory” argument which is another function, a callback.
This callback, accepts, in turn, one argument which is the element of the original array being currently processed. If the element passes the test (in this case if the length of the string is equal to 3), the element is inserted in the new array.
Map or array.prototype.map
The map
(array.prototype.map
) method, does something different. It also accepts a callback function as its only mandatory argument, but returns a new array composed by the elements resulting from applying said callback to all the elements of the original array.
An example will clarify everything. This time, suppose we want to obtain an array which should contain all the strings inside the “words” array, but in upper-case form. In just one line, we could write:
const uppercasedWords = words.map((element) => element.toUpperCase());
After executing the code above, the “uppercasedWords” array will be:
[ 'HOUSE', 'PEN', 'BOOK', 'COMPUTER', 'CAR' ]
The callback accepted as argument by map
, has only one mandatory argument, which is the element of the original array which is being processed. The value resulting from applying the callback to each element of the original array is returned (remember: arrow functions without curly braces uses implicit return) and so added to the new array. The result, in this case, is a new array composed by the upper-case version of all the elements in the original one.
Reduce or array.prototype.reduce
The reduce
, or array.prototype.reduce
method works in a different way: it accepts a callback which takes two mandatory arguments. The first one is the so called accumulator
, and the second one is the currentValue
. Instead of producing a new array, this higher order function uses the provided callback, also called reducer
, to reduce the array to one single value, which is returned. It is actually simpler than it looks, let’s see a basic example.
Suppose we have an array containing some numbers:
const numbers = [ 15, 0.50, 200 ];
Now, imagine we want to get the sum of all the numbers contained into the array. Again, we could use a loop, or, as we want to demonstrate, reduce
, in the following way:
let totalPrice = numbers.reduce((accumulator, currentValue) => accumulator + currentValue);
The reduce
method, as said above, accepts a callback function which takes two mandatory arguments. The first one is the accumulator
: this argument will accumulate the results produced each time the callback function is called. The second one is currentValue
, which represents the current element of the original array that is being processed.
One important thing to notice, is that, if no specified otherwise (we will see in a moment how we can do it), the first time the callback function is called, the value of the accumulator will be the first element of the array. We can realize that by simply logging the value of the accumulator
and of the currentValue
, each time the callback is executed:
let totalPrice = numbers.reduce((accumulator, currentValue) => {
console.log(accumulator, currentValue);
return accumulator + currentValue;
});
The output of the code above will be:
15 0.5 15.5 200
As you can notice, if an initial value for the accumulator
is not explicitly provided, the first element of the array is used (15), and, very important thing, the index
of the first element processed by the array, is1
, so, in this case the first element to be processed is 0.5
(the second one).
If you think about it, this makes sense: otherwise the first element of the array would be counted two times! (It may be worth noticing that we could have specified manually the index of the first element of the array to be processed, by using the currentIndex
optional argument of the callback, providing it after currentValue
). As expected, the final value of totalPrice
will be 215.5
:
totalPrice 215.5
In the example above, the elements of the original array, “numbers”, were simple numbers, so primary types
in Javascript. What if they were objects? Suppose we have an array of objects, each having three properties: a name, a price, and a price currency:
const items = [
{ name: 'book', price: 15, currency: 'EUR' },
{ name: 'car', price: 15000, currency: 'EUR' },
{ name: 'laptop', price: 1200, currency: 'EUR'}
];
What we want to obtain here, is the sum of all item prices. A problem immediately arises: we don’t want to sum each item of the array directly, since in this case we are working with objects, but the price
property of each one. We should therefore make use of an optional parameter accepted by reduce
, which is initialValue
:
let finalPrice = items.reduce((accumulator, currentValue) => accumulator + currentValue.price, 0)
The finalPrice
we obtain, as expected, is 16215
. If we had not specified the initialValue
, providing it after the callback function (0), the first element of the “items” array would have been used as the starting value for the accumulator
. Since this is an object, the result would not have been as expected!
Conclusions
In this tutorial we learned to know what defines an higher order function, and why is it possible to use them in Javascript. We also learned to know and use three higher order functions contained in the standard Javascript library, such as filter
, map
and reduce
. If you are interested in other Javascript topics, you can check our tutorials on promises or arrow functions.