Simplify your JavaScript
Use .map(), .reduce(), and .filter()
Functional programming has been making quite a splash in the development world these days.
This article will take a close look at map, filter, and reduce. Wrapping your head around these three functions is an important step towards being able to write clean, functional code, and it opens the doors to the vastly powerful techniques of functional and reactive programming.
Curious? Let’s dive in.
.map()
Let me explain how it works with a simple example. Let’s say you have received an array containing multiple objects — each one representing a person. The thing you really need in the end, though, is an array containing only the id of each movie.
// What we have at the momentvar movies = [
{ id: 75, name: 'JAWS' },
{ id: 94, name: 'Pulp Fiction' },
{ id: 84, name: 'Star Wars: The Phantom Menace' },
{ id: 77, name: 'Star Wars A New Hope' }
];// What we need[75, 94, 84, 77]
There are many ways to achieve this. You might want to do it by creating an empty array, then using .forEach()
, .for(...of)
, or a simple .for()
to meet your goal, right?
Let’s compare, the .forEach()
with the .map()
.
var moviesIds = [];movies.forEach(function (movie) {
moviesIds.push(movie.id);
});
Notice how you have to create an empty array beforehand if we use the .forEach()
? Let’s look how we can do it with the .map()
.
var moviesIds = movies.map(function (movie) {
return movie.id
});
We can even be more concise with arrow functions
const moviesIds = movies.map(movie => movie.id);
.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 pretty much anything (integer, string, object, etc.) and must be instantiated or passed when calling .reduce()
.
Let’s say we have an array with those movies again and their respective years:
var movies = [
{
id: 10,
name: "JAWS",
years: 1975,
},
{
id: 2,
name: "Pulp Fiction",
years: 1994,
},
{
id: 41,
name: "Star Wars: The Phantom Menace",
years: 1999,
},
{
id: 99,
name: "Star Wars A New Hope",
years: 1977,
}
];
We need to know the total years of all of them. With .reduce()
, it’s pretty straightforward:
var totalYears = movies.reduce(function (accumulator, movie) {
return accumulator + movie.years;
}, 0);
After running the callback for each element of the array, reduce will return the final value of our accumulator (in our case: 7945
).
Let’s see how this can be shortened with ES6’s arrow functions:
const totalYears = movies.reduce((acc, movie) => acc + movie.years, 0);
Now let’s say I want to find which movie is the eldest one. For that, I can use reduce as well:
var mostOldMov = movies.reduce(function (oldest, movie) {
return (oldest.years || 0) > movie.years ? oldest : movie;
}, {});
As you can see, using .reduce()
is an easy way to generate a single value or object from an array.
.filter()
What if you have an array, but only want some of the elements in it?
Here’s our data:
var movies = [
{
id: 10,
name: "JAWS",
type: Adventure,
},
{
id: 2,
name: "Pulp Fiction",
type: Crime,
},
{
id: 41,
name: "Star Wars: The Phantom Menace",
type: SiFi,
},
{
id: 99,
name: "Star Wars A New Hope",
type: SiFi,
}
];
Say we want two arrays now: one for SiFi ones, the other one for rest. With .filter()
it couldn’t be easier!
var siFiMovies = movies.filter(function (movie) {
return movie.type === "SiFi";
});var otherMovies = movies.filter(function (movie) {
return movie.type !== "SiFi";
});
That’s it! And it’s even shorter with arrow functions:
const siFiMovies = movies.filter(movie => movie.type === "SiFi");
const otherMovies = movies.filter(movie => movie.type !== "SiFi");