Map, reduce, and filter are three very useful array methods in JavaScript that give developers a ton of power in a short amount of space. Let’s jump right into how you can leverage (and remember how to use!) these super handy methods.
Array.map()
Array.map()
updates each individual value in a given array based on a provided transformation and returns a new array of the same size. It accepts a callback function as an argument, which it uses to apply the transform.
let newArray = oldArray.map((value, index, array) => {
...
});
A mnemonic to remember this is MAP: Morph Array Piece-by-Piece.
Instead of a for-each loop to go through and apply this transformation to each value, you can use a map. This works when you want to preserve each value, but update it. We’re not potentially eliminating any values (like we would with a filter), or calculating a new output (like we would use reduce for). A map lets you morph an array piece-by-piece. Let’s take a look at an example:
[1, 4, 6, 14, 32, 78].map(val => val * 10)
// the result is: [10, 40, 60, 140, 320, 780]
In the above example, we take an initial array ([1, 4, 6, 14, 32, 78]
) and map each value in it to be that value times ten (val * 10
). The result is a new array with each value of the original array transformed by the equation: [10, 40, 60, 140, 320, 780]
.

Array.filter()
Array.filter()
is a very handy shortcut when we have an array of values and want to filter those values into another array, where each value in the new array is a value that passes a specific test.
This works like a search filter. We’re filtering out values that pass the parameters we provide.
For example, if we have an array of numeric values, and want to filter them to just the values that are larger than 10, we could write:
[1, 4, 6, 14, 32, 78].filter(val => val > 10)
// the result is: [14, 32, 78]
If we were to use a map method on this array, such as in the example above, we would return an array of the same length as the original with val > 10
being the “transform,” or a test in this case. We transform each of the original values to their answer if they are greater than 10. It would look like this:
[1, 4, 6, 14, 32, 78].map(val => val > 10)
// the result is: [false, false, false, true, true, true]
A filter, however, returns only the true values. So the result is smaller than the original array or the same size if all values pass a specific test.
Think about filter like a strainer-type-of-filter. Some of the mix will pass through into the result, but some will be left behind and discarded.

Say we have a (very small) class of four dogs in obedience school. All of the dogs had challenges throughout obedience school and took a graded final exam. We’ll represent the doggies as an array of objects, i.e.:
const students = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Kitten",
finalGrade: 45
},
{
name: "Taco",
finalGrade: 100
},
{
name: "Lucy",
finalGrade: 60
}
]
If the dogs get a score higher than 70 on their final test, they get a fancy certificate; and if they don’t, they’ll need to take the course again. In order to know how many certificates to print, we need to write a method that will return the dogs with passing grades. Instead of writing out a loop to test each object in the array, we can shorten our code with filter
!
const passingDogs = students.filter((student) => {
return student.finalGrade >= 70
})
/*
passingDogs = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Taco",
finalGrade: 100
}
]
*/
As you can see, Boops and Taco are good dogs (actually, all dogs are good dogs), so Boops and Taco are getting certificates of achievement for passing the course! We can write this in a single line of code with our lovely implicit returns and then remove the parenthesis from our arrow function since we have single argument:
const passingDogs = students.filter(student => student.finalGrade >= 70)
/*
passingDogs = [
{
name: "Boops",
finalGrade: 80
},
{
name: "Taco",
finalGrade: 100
}
]
*/
Array.reduce()
The reduce()
method takes the input values of an array and returns a single value. This one is really interesting. Reduce accepts a callback function which consists of an accumulator (a value that accumulates each piece of the array, growing like a snowball), the value itself, and the index. It also takes a starting value as a second argument:
let finalVal = oldArray.reduce((accumulator, currentValue, currentIndex, array) => {
...
}), initalValue;

Let’s set up a cook function and a list of ingredients:
// our list of ingredients in an array
const ingredients = ['wine', 'tomato', 'onion', 'mushroom']
// a cooking function
const cook = (ingredient) => {
return `cooked ${ingredient}`
}
If we want to reduce the items into a sauce (pun absolutely intended), we’ll reduce them with reduce()
!
const wineReduction = ingredients.reduce((sauce, item) => {
return sauce += cook(item) + ', '
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom, "
That initial value (''
in our case) is important because if we don’t have it, we don’t cook the first item. It makes our output a little wonky, so it’s definitely something to watch out for. Here’s what I mean:
const wineReduction = ingredients.reduce((sauce, item) => {
return sauce += cook(item) + ', '
})
// wineReduction = "winecooked tomato, cooked onion, cooked mushroom, "
Finally, to make sure we don’t have any excess spaces at the end of our new string, we can pass in the index and the array to apply our transformation:
const wineReduction = ingredients.reduce((sauce, item, index, array) => {
sauce += cook(item)
if (index < array.length - 1) {
sauce += ', '
}
return sauce
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"
Now we can write this even more concisely (in a single line!) using ternary operators, string templates, and implicit returns:
const wineReduction = ingredients.reduce((sauce, item, index, array) => {
return (index < array.length - 1) ? sauce += `${cook(item)}, ` : sauce += `${cook(item)}`
}, '')
// wineReduction = "cooked wine, cooked tomato, cooked onion, cooked mushroom"
A little way to remember this is to recall how you make sauce: you reduce a few ingredients down to a single item.
Sing it with me!
I wanted to end this blog post with a song, so I wrote a little ditty about array methods that might just help you to remember them:
And of course I leave a comment with code that doesn’t work (backseat coding!). That should have been…
const wineReduction = ingredients.reduce((sauce, item) => ([sauce, cook(item)].filter(x => x).join(', ')), '');
This was awesome! Thanks for being such a creative human! :D
Cool explanations!
Though, I’d like to point out a potential pitfall in reduce. In the lambda, you wrote:
return sauce += cook(item) + ‘, ‘
However, there is no need to use += here, since the next call to the lambda will not use the same sauce, but will use the return value as its sauce.
Using + is enough. += is also very much not in the functional style of map/filter/reduce since it mutates sauce (even though it’s just a local variable).
For the second version where we have the check for the comma, we could save the temporary new sauce in a new variable, e.g.:
const nextSauce = sauce + cook(item);
I love the article and the song. I will use the 3 now.
This is great!
Can I contribute one small fix in the first
reduce
example.The second argument is outside of the bracket, it should be:
Very nicely explained and I like the song too :) Thank you
Amazing! Thanks
now I understand Array.map() and Array.filter() methods clearly I’ll go over the .reduce() method once again
Very nice article. Those three functions (methods) are very useful and it’d be great if more people knew about them.
One suggestion though; you can simplify your first reduce example quite a bit to just
ingredients.reduce((sauce, ingredient) => sauce + ‘, ‘ + ingredient)
It doesn’t add a comma before the first argument because it doesn’t call the function for the first argument at all, instead starting with the second and passing the first one as the accumulator.
Yeah, also thought about it!;)
Nice article and song! But reduce example seemed overcomplicated to me, it’s easier to get the separated cooked food with commas using
join(", ")
.Great article, but I think you glossed over an important detail about
reduce()
: if theinitialValue
parameter is not supplied, it defaults to the first element in the source array. You showed this in your output comment, but didn’t explain it exactly (you just said it would make the output “wonky”).This was really well explained, thank you. I got lost on the reduce section but the .map and .filter made those so much simpler than I have had them explained in the past.
Really nice presentation, but a couple things.
1) Your wording on map makes it sound like the initial array is getting mutated, but it’s not.
2) Your initial snippet for reduce is incorrect. Your initial value should be inside the parens.
let finalVal = oldArray.reduce((accumulator, currentValue, currentIndex, array) => {
…
}, initialValue);
other minor issues have already been mentioned by Aron.
Also of note,
return
is optional.const cook = (ingredient) => {return
cooked ${ingredient}
};could be
const cook = (ingredient) =>
cooked ${ingredient}
;ROFL…
You are crazy ! In a very positive way :-)