I was recently mentoring someone who had trouble with the .reduce()
method in JavaScript. Namely, how you get from this:
const nums = [1, 2, 3]
let value = 0
for (let i = 0; i < nums.length; i++) {
value += nums[i]
}
…to this:
const nums = [1, 2, 3]
const value = nums.reduce((ac, next) => ac + next, 0)
They are functionally equivalent and they both sum up all the numbers in the array, but there is a bit of paradigm shift between them. Let’s explore reducers for a moment because they’re powerful, and important to have in your programming toolbox. There are literally hundreds of other articles on reducers out there, and I’ll link up some of my favorites at the end.
What is a reducer?
The first and most important thing to understand about a reducer is that it will always only return one value. The job of a reducer is to reduce. That one value can be a number, a string, an array or an object, but it will always only be one. Reducers are really great for a lot of things, but they’re especially useful for applying a bit of logic to a group of values and ending up with another single result.
That’s the other thing to mention: reducers will not, by their nature, mutate your initial value; rather they return something else. Let’s walk over that first example so you can see what’s happening here. The video below explains:
It might be helpful to watch the video to see how the progression occurs, but here’s the code we’re looking at:
const nums = [1, 2, 3]
let value = 0
for (let i = 0; i < nums.length; i++) {
value += nums[i]
}
We have our array (1, 2, 3
) and the first value each number in the array will be added to (0
). We walk through the amount of the array and add them to the initial value.
Let’s try this a little differently:
const nums = [1, 2, 3]
const initialValue = 0
const reducer = function (acc, item) {
return acc + item
}
const total = nums.reduce(reducer, initialValue)
Now we have the same array, but this time we’re not mutating that first value. Instead, we have an initialValue
that will only be used at the start. Next, we can make a function that takes an accumulator
and an item. The accumulator is the collected value
returned in the last invocation that informs the function what the next value will be added to. In this case of addition, you can think of it as a snowball rolling down a mountain that eats up each value in its path as it grows in size by every eaten value.

We’ll use .reduce()
to apply the function and start from that initial value. This can be shortened with an arrow function:
const nums = [1, 2, 3]
const initialValue = 0
const reducer = (acc, item) => {
return acc + item
}
const total = nums.reduce(reducer, initialValue)
And then shortened some more! Implicit returns for the win!
const nums = [1, 2, 3]
const initialValue = 0
const reducer = (acc, item) => acc + item
const total = nums.reduce(reducer, initialValue)
Now we can apply the function right where we called it, and we can also plop that initial value directly in there!
const nums = [1, 2, 3]
const total = nums.reduce((acc, item) => acc + item,
An accumulator can be an intimidating term, so you can think of it like the current state of the array as we’re applying the logic on the callback’s invocations.
The Call Stack
In case it’s not clear what’s happening, let’s log out what’s going on for each iteration. The reduce is using a callback function that will run for each item in the array. IThe following demo will help to make this more clear. I’ve also used a different array ([1, 3, 6]
) because having the numbers be the same as the index could be confusing.
See the Pen showing acc, item, return by Sarah Drasner (@sdras) on CodePen.
When we run this, we’ll see this output in the console:
"Acc: 0, Item: 1, Return value: 1"
"Acc: 1, Item: 3, Return value: 4"
"Acc: 4, Item: 6, Return value: 10"
Here’s a more visual breakdown:
- It shows that the accumulator is starting at our initial value,
0
- Then we have the first item, which is 1, so our return value is
1
(0 + 1 = 1
) 1
becomes the accumulator on the next invocation- Now we have
1
as the accumulator and 3 is the item aince it is next in the array. - The returned value becomes
4
(1 + 3 = 4
) - That, in turn, becomes the accumulator and the next item at invocation is
6
- That results in
10
(4 + 6 = 10
) and is our final value since6
is the last number in the array
Simple Examples
Now that we’ve got that under our belt, let’s look at some common and useful things reducers can do.
How many of X do we have?
Let’s say you have an array of numbers and you want to return an object that reports the number of times those numbers occur in the array. Note that this could just as easily apply to strings.
const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82]
const result = nums.reduce((tally, amt) => {
tally[amt] ? tally[amt]++ : tally[amt] = 1
return tally
}, {})
console.log(result)
See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.
Wait, what did we just do?
Initially, we have an array and the object we’re going to put its contents into. In our reducer, we ask: does this item exist? If so, let’s increment it. If not, add it and set it to 1. At the end, please return the tally count of each item. Then, we run the reduce function, passing in both the reducer and the initial value.
Take an array and turn it into an object that shows some conditions
Let’s say we have an array and we want to create an object based on a set of conditions. Reduce can be great for this! Here, we want to create an object out of any instance of a number contained in the array and show both an odd and even version of this number. If the number is already even or odd, then that’s what we’ll have in the object.
const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82]
// we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => {
acc[item] = {
odd: item % 2 ? item : item - 1,
even: item % 2 ? item + 1 : item
}
return acc
}, {})
console.log(result)
See the Pen simplified reduce by Sarah Drasner (@sdras) on CodePen.
This will shoot out the following output in the console:
1:{odd: 1, even: 2}
3:{odd: 3, even: 4}
4:{odd: 3, even: 4}
5:{odd: 5, even: 6}
6:{odd: 5, even: 6}
82:{odd: 81, even: 82}
OK, so what’s happening?
As we’re going through every item in the array, we create a property for even and odd, and based on an inline condition with a modulus operator, we’ll either store the number or increment it by 1. The modulus operator is really good for this because it can quickly check for even or odd — if it’s divisible by two, it’s even, if not, it’s odd.
Other resources
At the top, I mentioned other posts out there that are handy resources to get more familiar with the role of reducers. Here are a few of my favorites:
- The MDN documentation is wonderful for this. Seriously, it’s one of their best posts, IMO. They also describe in a bit more detail what happens if you don’t provide an initial value, which we didn’t cover in this post.
- Daniel Shiffman is always amazing at explaining things on Coding Train.
- A Drip of JavaScript does a good job, too.
I am wondering if it would be possible to show the non .reduce() way of doing this and then showing the performance differences. I would like to know how people, when presented the two different options, intuit the purpose of the code.
Hi David! The performance bit is a great part to bring up, because you’re intuiting correctly- there are times when functional, and
.reduce()
, is not as performant, and not the right tool for the job. I’ll see if I can dig something up that illustrates. The trouble with benchmarks, though, is that they tend to have some fuzzy logic- the exact implementation really does matter, so it might lead people down the wrong path to think that one is always better than the other in every situation. Great observation!I love the video — a great way to visualize how reducers work!
Another upside of reducers over for loops is that they can be much more readable, especially when named.
Using your
sum
example,That’s a great point, Adam!
Just want to 2nd the point about the videos showing how reduce works. They were great. For people who are a bit more visual in their learning style this can really help them understand the concept being presented. Thanks for taking the extra time to create the videos.
I agree Adam! The readability is great. My favorite way to write these is as you did here … where the reducer function is a named function that is passed to the
[].reduce()
Readability matters
Thanks Sarah that makes sense of the reduce method, not something I have used much so far. Looking at the MDN docs for this, using it to flatten out arrays would be very useful
Flattening is a great use for reduce — there is also currently a proposal to add a
flat()
method. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatHave to admit the only question I ask is why! The ‘for loop’ is pretty obvious and it says it all.
Guess this is really just a lambda function, so why not call it that. Even then a lambda is overkill for something like this.
Maybe its just me but languages (not just JS) get more complicated without any really good reason or real benefit!
But guess it keeps the tools and educators in a job, as well as the bug hunters as the new tools/features get messed up by the users.
or maybe I’m just an old school reactionary :)
Nonetheless good explanation – thanks
You certainly don’t have to do functional programming if it doesn’t suit you.
You point to other articles, which I’ve read, but you’ve literally reduced it into terms I can understand.