Iterator.prototype.reduce()
Fold an iterator down to a single value by running a reducer over every element.
reduce(callbackFn)
reduce(callbackFn, initialValue)- Added in JavaScript ES2025 (Baseline March 2025)
Parameters
| Parameter | Type | Description |
|---|---|---|
$callbackFn | Function | Called as callbackFn(accumulator, currentValue, currentIndex); its return value becomes the accumulator for the next call. accumulator starts as initialValue when given, otherwise as the first element. currentIndex is 0 on the first call when initialValue is supplied, and 1 otherwise. |
$initialValueoptional | any | The starting accumulator. When omitted, the first element of the iterator is used instead and the callback is first called with the second element. |
Return value
anyThe single value produced by running the reducer across every element of the iterator — the final accumulator.
Errors
Throws a TypeError if the iterator produces no elements and no initialValue was provided, and if callbackFn is not callable.
Unlike map() or filter(), reduce() is a terminal operation: it is not lazy, it drains the iterator immediately and hands back a value rather than another helper. That makes it the natural end of a pipeline — the point where a stream becomes a total, an object, or a string.
When to reach for it
- Summing, counting, or finding a max over a sequence you never want to materialise.
- Building a lookup object or a
Mapfrom streamed records. - Ending a chain that already used
take()to bound an infinite source.
What trips people up
It never terminates on an infinite iterator. There is no short-circuit — every element is consumed — so bound the source with take() first.
Omitting initialValue on a possibly empty iterator throws a TypeError rather than returning undefined. Since an iterator has no length you often cannot tell in advance whether it is empty, so supplying an explicit initial value is the safer default. It also fixes the accumulator's type, which stops the first element from silently becoming the seed.
Note the index: with an initial value the first call sees index 0; without one it starts at 1.
Example
When to use it
- Sum the first ten values of an unbounded generator
- Group streamed order records into a totals-by-customer object
- Compute a running maximum over Map values without building an array
Frequently asked questions
Why does reduce() throw TypeError on an empty iterator?
Because with no elements and no initialValue there is nothing to use as the starting accumulator, and the specification treats that as an error rather than returning undefined. Always pass an initial value when the source might be empty — you usually cannot check an iterator for emptiness without consuming it.
Can reduce() work on an infinite generator?
No. It consumes every element and has no early exit, so it will loop forever. Bound the source first with take(n), or use some()/find(), which do short-circuit, when you only need to know whether a condition is met.
Should I use reduce() or toArray() then Array.prototype.reduce()?
Use the iterator version — it folds as it pulls, so no intermediate array is allocated. Collecting into an array first doubles the memory for no benefit unless you need the array for something else as well.
More examples
Building an object from streamed records
The initial {} sets the accumulator type; each callback mutates and returns it. Forgetting the return statement is the classic bug here — the accumulator becomes undefined on the next pass.
const orders = [
{ user: "ana", total: 30 },
{ user: "bo", total: 12 },
{ user: "ana", total: 5 },
];
const totals = orders.values().reduce((acc, o) => {
acc[o.user] = (acc[o.user] ?? 0) + o.total;
return acc;
}, {});
console.log(totals); // { ana: 35, bo: 12 }The index differs with and without a seed
Without an initial value the first element becomes the accumulator and the callback starts at index 1, so it runs twice. With a seed it runs three times starting at index 0.
const seen = [];
[10, 20, 30].values().reduce((acc, v, i) => {
seen.push(i);
return acc + v;
});
console.log(seen); // [1, 2]
const seenSeeded = [];
[10, 20, 30].values().reduce((acc, v, i) => {
seenSeeded.push(i);
return acc + v;
}, 0);
console.log(seenSeeded); // [0, 1, 2]
Discussion