JavaScript Array Reduce Method: Complete Guide
reduce() turns an array into a single value by running an accumulator function on every element. Learn summing, grouping, flattening, and more.
reduce() is the most powerful and flexible array method in JavaScript. It takes an array and reduces it to a single value -- a number, a string, an object, or even another array. Every other array method can be implemented with reduce().
The accumulator starts at an initial value. For each element, the callback updates the accumulator. After the last element, the accumulator becomes the final result.
Syntax and the Accumulator Pattern
reduce() takes a callback and an optional starting value, then calls the callback once per element, passing along whatever it returned last time:
array.reduce((accumulator, element) => {
return newAccumulator;
}, initialValue);There are four key pieces:
| Piece | Description |
|---|---|
accumulator | The value carried forward from the previous iteration |
element | The current array element |
| Return value | Becomes the accumulator for the next iteration |
initialValue | The starting value of the accumulator (optional, but recommended) |
Here is the simplest example, summing numbers, which shows the pattern in its smallest useful form:
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 10Tracing through each call shows exactly how the accumulator grows on every step, from the initial value all the way to the final result:
Start: acc = 0 (initial value)
Element 1: acc = 0 + 1 = 1
Element 2: acc = 1 + 2 = 3
Element 3: acc = 3 + 3 = 6
Element 4: acc = 6 + 4 = 10
Final: 10Always Provide an Initial Value
Without an initial value, reduce() uses the first array element as the accumulator and starts from the second element. This works for simple sums but fails on empty arrays:
const numbers = [1, 2, 3];
const sum = numbers.reduce((acc, n) => acc + n); // ok: acc starts at 1
console.log(sum); // 6
const empty = [];
const result = empty.reduce((acc, n) => acc + n); // TypeError!Always provide an initial value. It makes the behavior predictable and avoids runtime errors.
Building an Object with reduce()
reduce() can build objects. A common use is counting occurrences:
const fruits = ["apple", "banana", "apple", "orange", "banana", "apple"];
const counts = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(counts); // { apple: 3, banana: 2, orange: 1 }Notice that the callback must return the accumulator each time. Forgetting the return statement is the most common reduce() bug, and it silently breaks the whole chain of iterations:
// Wrong: forgets to return the accumulator
const counts = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
}, {});
console.log(counts); // undefined (accumulator was lost)Grouping Objects by a Property
reduce() is excellent for grouping an array of objects by a shared key. The accumulator starts as an empty object, and each element adds itself to the array under its matching key:
const people = [
{ name: "Alice", role: "developer" },
{ name: "Bob", role: "designer" },
{ name: "Carol", role: "developer" },
{ name: "Dave", role: "designer" }
];Each person gets pushed into the array under their role, creating that array the first time a new role is seen, so no role is ever left uninitialized:
const grouped = people.reduce((acc, person) => {
const key = person.role;
if (!acc[key]) acc[key] = [];
acc[key].push(person);
return acc;
}, {});The result is one array per role, each holding the full person objects that share that role, which is exactly the shape you would want for rendering grouped lists in a UI:
console.log(grouped.developer.map(p => p.name)); // ["Alice", "Carol"]
console.log(grouped.designer.map(p => p.name)); // ["Bob", "Dave"]Flattening an Array of Arrays
Before flat() existed, reduce() was the standard way to flatten a nested array, using concat() to merge each inner array into the accumulator:
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flat); // [1, 2, 3, 4, 5, 6]Today arr.flat() or arr.flatMap() is cleaner for this. For one-to-many mapping with flattening, see flatMap.
Finding Maximum and Minimum
reduce() can find the minimum or maximum element by custom logic, which is useful for objects where Math.min() and Math.max() do not directly apply:
const products = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 29 },
{ name: "Monitor", price: 299 }
];
const cheapest = products.reduce((min, product) =>
product.price < min.price ? product : min
);
console.log(cheapest); // { name: "Mouse", price: 29 }This omits the initial value on purpose. Since the array is known to be non-empty, the first product safely becomes the starting min. If the array might be empty, provide an initial value to avoid a TypeError.
reduce() vs Other Methods
| Task | With reduce() | Simpler Alternative |
|---|---|---|
| Transform elements | reduce((acc, n) => [...acc, n*2], []) | map(n => n * 2) |
| Select elements | reduce((acc, n) => n>5 ? [...acc, n] : acc, []) | filter(n => n > 5) |
| Check any/all | reduce((acc, n) => acc && n>0, true) | every(n => n > 0) |
| Sum values | reduce((a, n) => a + n, 0) | (reduce is best here) |
| Group by key | (reduce is best here) | (reduce is best here) |
Use the simplest method that works. If map() or filter() can do the job, use them. Reach for reduce() when the result is a different shape from the input -- a single value, a grouped object, or a custom data structure.
Common Mistakes
Forgetting the initial value. Calling reduce() on an empty array with no initial value has nothing to use as a starting accumulator, so it throws instead of returning a default:
const empty = [];
empty.reduce((acc, n) => acc + n); // TypeError
empty.reduce((acc, n) => acc + n, 0); // 0Forgetting to return the accumulator. Mutating the accumulator without returning it loses the value on the very next call, since reduce() always uses whatever the callback returned:
const result = [1, 2, 3].reduce((acc, n) => {
acc.push(n * 2); // mutates but doesn't return
}, []);
console.log(result); // undefinedAdding the missing return fixes it, since the accumulator now carries forward correctly on every call instead of silently turning into undefined:
const resultFixed = [1, 2, 3].reduce((acc, n) => {
acc.push(n * 2);
return acc;
}, []);
console.log(resultFixed); // [2, 4, 6]When the callback uses curly braces {}, you need an explicit return. Arrow functions with a single expression (() => expression) return implicitly.
Now that you understand reduce(), learn how to select specific elements with filter for creating subsets of your data.
Rune AI
Key Insights
- reduce() processes every element and accumulates a single result value.
- The accumulator carries the result from one iteration to the next.
- Always provide an initial value to avoid errors on empty arrays.
- reduce() can sum numbers, group objects, flatten arrays, and build any data structure.
- Keep reduce() callbacks readable. If they get complex, use named functions.
Frequently Asked Questions
What happens if I call reduce() on an empty array without an initial value?
When should I use reduce() instead of a for loop?
Is reduce() always the right choice for summing numbers?
Conclusion
reduce() is the most powerful array method in JavaScript. It can replace map(), filter(), and nearly any other array transformation. But with great power comes a responsibility to keep it readable. Use reduce() when the transformation is naturally an accumulation -- summing, grouping, flattening, or building up a result. When the logic gets complex, break it into named functions or use a simpler method.
More in this topic
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.
How to Loop Through Arrays Using JS for Loops Guide
Looping through arrays is the most practical use of JavaScript for loops. Learn how to access each element by index, avoid off-by-one errors, and choose between for, for...of, and forEach.