Array.prototype.reduce()

The general-purpose one: map, filter and join can all be written with it. Omitting the initial value is what turns it from useful into a source of runtime errors.

Array methodES5 (2009)Live demo
Common call
items.reduce((acc, x) => acc + x, 0)
Returns
a single value of whatever type the accumulator is
Replaces
a for loop that builds up a running total
Watch out
no initialValue on an empty array is a TypeError
array.reduce(callback[, initialValue])
→ any

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
initialnumberinitial accumulator
Output
[1, 2, 3].reduce((a, b) => a + b, 0)
6

The callback receives the running accumulator and the next element, and whatever it returns becomes the accumulator for the next round. Starting from 10 rather than 0 simply shifts the result by 10. The empty case is the one that matters: because an initial value is supplied, it comes straight back rather than throwing — which is exactly what happens without one.

Parameters

NameTypeRequiredDescription
callbackFunctionyesCalled as callback(accumulator, element, index, array). Its return value becomes the accumulator for the next element.
initialValueanyno (first element)Starting accumulator. Omitted, the first element is used and iteration starts at the second — which is why an empty array then throws.

Return value

any — Whatever the callback returned on the final iteration. With an initialValue and an empty array, that value is returned untouched.

Common patterns

Sum or total
The canonical use, and the one always worth an explicit 0.
const total = prices.reduce((acc, p) => acc + p, 0);
Group into an object
The accumulator does not have to be a number.
const byType = items.reduce((acc, i) => {
  (acc[i.type] ??= []).push(i);
  return acc;
}, {});
Count occurrences
A tally object built in one pass.
const counts = words.reduce((acc, w) => {
  acc[w] = (acc[w] ?? 0) + 1;
  return acc;
}, {});

Examples

1. Sum
[1, 2, 3].reduce((a, b) => a + b, 0)
Returns
6
2. From 10
[1, 2, 3].reduce((a, b) => a + b, 10)
Returns
16
3. No initial works
[1, 2, 3].reduce((a, b) => a + b)
Returns
6
4. Empty + initial
[].reduce((a, b) => a + b, 0)
Returns
0
5. Empty, no initial
[].reduce((a, b) => a + b)
Returns
TypeError: Reduce of empty array with no initial value
6. Build an object
['a','b'].reduce((o, k) => ({...o, [k]: true}), {})
Returns
{ a: true, b: true }

Pitfalls

1. No initial value on an empty array throws
The single reason to always pass one. Without it reduce uses the first element as the seed, and an empty array has none — so it is a TypeError rather than a sensible zero. The bug hides until the data happens to be empty.
Throws on empty
[].reduce((a, b) => a + b)
TypeError: Reduce of empty array with no initial value
Always seed it
[].reduce((a, b) => a + b, 0)
0
2. Forgetting to return the accumulator
A braced callback must return the accumulator every time. Miss it on any path and the accumulator becomes undefined for the rest of the run, which usually surfaces as NaN or a crash on the next property access.
Nothing returned
[1, 2].reduce((acc, x) => { acc.total = x; }, {})
TypeError on the second element
Return it
[1, 2].reduce((acc, x) => { acc.total = x; return acc; }, {})
{ total: 2 }
3. Spreading into the accumulator is quadratic
A tidy-looking one-liner that copies the whole accumulator on every element. Fine for ten items, a real problem for ten thousand — mutate the accumulator instead, since you own it.
Copies each time
items.reduce((o, k) => ({...o, [k]: true}), {})
O(n²)
Mutate and return
items.reduce((o, k) => { o[k] = true; return o; }, {})
O(n)
4. Using reduce where a simpler method fits
reduce can express map, filter and join, but it reads far worse than any of them. Reach for it when you genuinely collapse to one value that is not just a transformed list.
Reduce as map
items.reduce((acc, x) => [...acc, x * 2], [])
works, but obscure and quadratic
Just map
items.map(x => x * 2)
clear and linear

When to use

Use it
  • Summing or otherwise aggregating to a single value
  • Building an object or Map from an array in one pass
  • Counting or grouping
  • Any fold where the accumulator type differs from the element type
Reach for something else
  • One-to-one transformation → map
  • Selecting a subset → filter
  • Joining into a string → join
  • The accumulator is just a growing array → map or flatMap

Notes

Complexity
O(n) for the iteration, plus whatever the callback costs — spreading the accumulator makes it O(n²)
Return
The final accumulator; the original array is never modified
CPython impl
V8: Builtins-array-reduce.tq
Memory
Only the accumulator, unless the callback allocates per element
Thread-safe
Single-threaded; mutating the source inside the callback is undefined behaviour for unvisited indices

FAQ

Yes, unless you have already proved the array is non-empty. It costs nothing, it removes the empty-array TypeError entirely, and it makes the accumulator type obvious to the next reader.

items.reduce((a, b) => a + b, 0)

History

ES5
Array.prototype.reduce standardised in 2009, alongside reduceRight.
ES2019
flat and flatMap arrived, removing the most common reduce misuse.