JavaScript Reduce
What is the Reduce method?
Let's try to simplify and understand JavaScript's reduce method.
Reduce is a method that can be used on arrays to take multiple values and reduce them to a single value.
For example, we could take an array of numbers and reduce them to a single value representing the sum of those numbers.
Or, we could take an array of objects and total up the values from a specific property on those objects.
We could also, for example, take an array of letter strings and reduce those letters to a single string.
Reduce is like a "Swiss Army Knife" of JavaScript array methods!
A Code Example
Let's move forward and see reduce in action.
For this example, we'll see how we can get the total value of a particular property from objects in an array.
Let's create a const called spiceGirls and set it equal to an array of objects. Notice that each one of these objects has a name property and a numCats property(short for number of cats).
const spiceGirls = [
{ name: "ginger", numCats: 2 },
{ name: "sporty", numCats: 1 },
{ name: "baby", numCats: 0 },
{ name: "posh", numCats: 3 },
{ name: "scary", numCats: 6 },
];
With reduce, we can collectively sum up the number of cats the Spice Girls have. Essentially, we want to take this array of objects and reduce it to a single numeric value.
And that's one of the cool things about reduce. We can start with an array and reduce it to a value of several different types: object, array, simple string, numeric, etc.
In this case, we'll reduce it to a single number.
The first thing we'll do is take that spiceGirls array and call reduce on it.
const totalCats = spiceGirls.reduce(() => {});
Now, reduce takes two arguments:
- a callback function (aka the reducer)
- an initial value
Let's set our initial value to zero.
const totalCats = spiceGirls.reduce(() => {}, 0);
Now let's look at the reducer callback function.
The reducer callback accepts at least two arguments:
- the accumulator (accum for short)
- current value (currValue for short)
(As with array methods like map and filter, current value represents each element in the array).
const totalCats = spiceGirls.reduce((accum, currValue) => {}, 0);
So reduce will iterate(loop) through each element of the array (which will be the current value for that iteration).
And our accumulator will be initialized to a value of zero.
Think of the accumulator as a sponge. On each iteration, it's going to "soak" up a calculation.
Then, we'll return the result of that calculation as the new accumulator value for the next iteration.
For this example, we add the accumulator value to currValue.numCats. (numCats is the particular property whose value we want to tally up on each iteration).
BTW, a critical but often forgotten aspect of working with reduce is that the new value must be returned.
And logging totalCats to the console yields a single numeric value of 12.
const totalCats = spiceGirls.reduce((accum, currValue) => {
return accum + currValue.numCats;
}, 0);
console.log(totalCats);
A Closer Look at Initial Value
Let's take a closer look at that initial value we had set to zero.
Since we had provided the initial value, the accumulator was initialized to 0. This sets the current value to the first element in the array for the first iteration.
const totalCats = spiceGirls.reduce((accum, currValue) => {
return accum + currValue.numCats;
}, 0);
And because we provided that initial value as a numeric value of 0, the calculation returned: 0 + 2. (2 being the number of cats from the first object in the array).
const spiceGirls = [
{ name: "ginger", numCats: 2 },
{ name: "sporty", numCats: 1 },
{ name: "baby", numCats: 0 },
{ name: "posh", numCats: 3 },
{ name: "scary", numCats: 6 },
];
However, if we omit the initial value, the console will log [object Object] 1036.
So when the initial value is omitted, accum is initialized to the first element in the array. And currValue gets initialized to the second element in the array.
Since we're targeting the numCats property on each iteration, the object tries adding to a numeric value. That's why we get [object Object] 1036 in the console rather than a single numeric value.
If you're more of a visual learner, check out the video version of this article: