Out of map(), filter(), and reduce(), this last one is usually the one that takes people the longest to actually feel comfortable with. map() transforms, filter() narrows down, and reduce() does something a little different, it takes an entire array and boils it down into a single value, a sum, an object, a count, basically anything you can build up piece by piece. Once it clicks though, it genuinely becomes one of the most powerful tools in your array toolbox.
Let's go through how it actually works, step by step, since that's usually where the confusion starts.
Table of Contents
The Basic Idea
let numbers = [1, 2, 3, 4]; let total = numbers.reduce((sum, current) => sum + current, 0); console.log(total); // 10There are two parts worth understanding here. The 0 at the end is the starting value, where the running total begins. And sum is that running total, carried forward and updated with each item as reduce() works through the array.
Walking Through It Step by Step
This is genuinely the best way to understand reduce(), actually tracing what happens on each pass.
let numbers = [1, 2, 3, 4];
numbers.reduce((sum, current) => {
console.log(`sum: ${sum}, current: ${current}`);
return sum + current;
}, 0);
// sum: 0, current: 1 -> returns 1
// sum: 1, current: 2 -> returns 3
// sum: 3, current: 3 -> returns 6
// sum: 6, current: 4 -> returns 10
Each time, whatever you return becomes the sum for the next round. By the end, that final returned value is what reduce() hands back to you.It's Not Just for Adding Numbers
This is the part a lot of people miss early on, reduce() can build up any kind of result, not just a total.
Counting occurrences:
let fruits = ["apple", "banana", "apple", "mango", "apple"];
let counts = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(counts); // { apple: 3, banana: 1, mango: 1 }
Grouping objects by a property:
let people = [
{ name: "Vi", city: "Bangalore" },
{ name: "Sam", city: "Mumbai" },
{ name: "Alex", city: "Bangalore" }
];
let grouped = people.reduce((acc, person) => {
acc[person.city] = acc[person.city] || [];
acc[person.city].push(person.name);
return acc;
}, {});
console.log(grouped);
// { Bangalore: ["Vi", "Alex"], Mumbai: ["Sam"] }
Flattening a nested array:
let nested = [[1, 2], [3, 4], [5]]; let flat = nested.reduce((acc, arr) => acc.concat(arr), []); console.log(flat); // [1, 2, 3, 4, 5]
Notice the starting value changes depending on what you're building, 0 for a sum, {} for an object, [] for an array. That starting value is really what shapes what reduce() ends up giving you back.
A Common Mistake: Forgetting to Return
let numbers = [1, 2, 3];
let broken = numbers.reduce((sum, n) => {
sum + n; // no return!
}, 0);
console.log(broken); // undefined
let fixed = numbers.reduce((sum, n) => {
return sum + n;
}, 0);
console.log(fixed); // 6
A Common Mistake: Skipping the Starting Value
Leaving out the second argument is technically allowed, but it changes behavior in a way that catches people off guard, especially on empty arrays.let empty = []; console.log(empty.reduce((sum, n) => sum + n, 0)); // 0, safe console.log(empty.reduce((sum, n) => sum + n)); // TypeError!Without a starting value, reduce() uses the array's first item as the starting point instead, and an empty array has nothing to start with, so it throws an error. It's a good habit to always pass a starting value explicitly, even when it feels obvious.
Conclusion
reduce() has a reputation for being the confusing one of the bunch, but really, it's just a loop that carries a running result forward with each step. The starting value sets the shape of what you're building, and whatever you return each time becomes the next round's starting point. Once you've traced through it step by step a couple of times, it stops feeling abstract and starts feeling like one of the most flexible tools available for working with arrays.Frequently Asked Questions (FAQs)
1.When should I use reduce() instead of map() or filter()?2.Why does reduce() throw an error on an empty array sometimes?Use it when you need to boil an entire array down into one single value, a sum, a count, a grouped object, rather than transforming or narrowing the array itself. If you just need a new array back, map() or filter() are usually the simpler choice.
3.Can reduce() return something other than a number?It only happens if you leave out the starting value. Without one, reduce() tries to use the array's first item as a starting point, and an empty array has nothing to use, so it throws an error instead.
Yes, genuinely anything, an object, an array, a string, even a boolean. Whatever starting value you give it shapes what kind of result you'll get back.
0 Comments