Array.prototype.reduce()

Folds an array left to right into a single accumulated value.

Signature
reduce(callbackFn)
reduce(callbackFn, initialValue)
  • Added in JavaScript ES5 (2009)

Parameters

ParameterTypeDescription
$callbackFnFunctionThe reducer, called with (accumulator, currentValue, currentIndex, array). Its return value becomes the accumulator for the next call.
$initialValueoptionalany= array[0]Starting value for the accumulator. If omitted, array[0] is used as the accumulator and iteration begins at index 1.

Return value

anyThe single value produced by running the reducer over every element; if the array has one element and no initialValue, that element is returned without calling the callback.

Errors

TypeError if the array contains no elements and no initialValue was supplied.

reduce() collapses many values into one. The callback receives the running accumulator and the current element, and whatever it returns becomes the accumulator for the next element. The accumulator does not have to be a number — objects, arrays, Maps and even functions are all common.

Always pass initialValue

Omitting the second argument makes reduce() use array[0] as the seed and start at index 1. On an empty array there is no element 0 to borrow, so it throws TypeError: Reduce of empty array with no initial value. Since empty arrays are usually the runtime case you did not test, supply the seed: reduce(fn, 0) or reduce(fn, {}). The seed also pins the accumulator's type, which stops sums from turning into string concatenation.

What trips people up

Every branch of the callback must return the accumulator. Writing acc[key] = value without a trailing return acc hands undefined to the next iteration and everything after it fails.

Reaching for reduce() when map() or filter() would do makes code harder to read for no gain. Save it for genuine folds: totals, groupings and single-pass pipelines.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Total the line items in a shopping cart
  • Group records into an object keyed by category
  • Count occurrences of each value into a tally object
  • Compose a pipeline of transform functions into one function

Frequently asked questions

Why does reduce() throw 'Reduce of empty array with no initial value'?

Because with no initialValue reduce() takes array[0] as the seed, and an empty array has no element 0. Pass an explicit initial value — reduce(fn, 0) returns 0 for an empty array instead of throwing.

What is the difference between reduce() and forEach()?

reduce() threads an accumulator through the callback and returns a value; forEach() returns undefined and relies on side effects. If you are pushing into an outer variable inside forEach, reduce() usually expresses the same thing without the external state.

Is reduce() slower than a for loop?

Marginally, because of the per-element function call, and it is much slower if the callback copies the accumulator each pass, such as returning { ...acc, [k]: v }. That turns an O(n) fold into O(n²) — mutate the accumulator and return it instead.

More examples

Grouping records by a key

Prints { eng: ['Ada', 'Ray'], ops: ['Lin'] }. The seed {} makes the accumulator an object rather than the first record, and the explicit return acc on the last line of the callback is what keeps the accumulator alive across iterations.

Example · javascript
const people = [
  { name: "Ada", dept: "eng" },
  { name: "Lin", dept: "ops" },
  { name: "Ray", dept: "eng" },
];

const byDept = people.reduce((acc, p) => {
  (acc[p.dept] ??= []).push(p.name);
  return acc;
}, {});

console.log(byDept);

Building a pipe() out of reduce

Prints 64. The accumulator here is the data flowing through the pipeline, not a total: 3 becomes 4, then 8, then 64. This is the left-to-right order; reduceRight() gives you compose() with the same body.

Example · javascript
const inc = (n) => n + 1;
const dbl = (n) => n * 2;
const sq = (n) => n * n;

const pipe = (...fns) => (x) => fns.reduce((value, fn) => fn(value), x);

console.log(pipe(inc, dbl, sq)(3));

Discussion

  • Be the first to comment on this lesson.