Array reduce() method
reduce() is one of the most powerful and versatile array methods in JavaScript: it folds an array step by step into a single value. That value can be a number, a string, an object, a new array or any other structure, which is why reduce() covers almost every data aggregation task.
Theory
TL;DR
reduce()walks the array from left to right and accumulates the result in an accumulator.- The callback has the signature
(accumulator, currentValue, index, array)and must return the new accumulator. - The second argument,
initialValue, sets the starting value and the type of the result. - Without
initialValuethe first element becomes the first accumulator, and an empty array throws aTypeError. - For a simple per element transformation prefer
map(), for selection preferfilter(), and reach forreduce()when you need one summary value.
Quick example
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 10Step by step it works like this:
acc = 0(the initial value)- 0 + 1 -> 1
- 1 + 2 -> 3
- 3 + 3 -> 6
- 6 + 4 -> 10
Syntax and parameters
const result = array.reduce((accumulator, currentValue, index, array) => {
return newAccumulatorValue;
}, initialValue);| Argument | Description |
|---|---|
accumulator | the accumulated value, that is whatever the previous iteration returned |
currentValue | the current array element |
index | the index of the current element |
array | the array the method was called on |
initialValue | the starting value of the accumulator, formally optional but strongly recommended |
Typical use cases
Counting elements that satisfy a condition. reduce() is often used for aggregation: counts, statistics, merging.
const users = [
{ name: 'Tim', age: 25 },
{ name: 'Alex', age: 17 },
{ name: 'John', age: 30 }
];
const adultsCount = users.reduce((acc, user) => {
return user.age >= 18 ? acc + 1 : acc;
}, 0);
console.log(adultsCount); // 2Turning an array into an object. Very handy when data has to be reshaped into another structure, for example a lookup dictionary.
const fruits = ['apple', 'banana', 'cherry'];
const fruitMap = fruits.reduce((acc, fruit, index) => {
acc[index] = fruit;
return acc;
}, {});
console.log(fruitMap);
// { 0: 'apple', 1: 'banana', 2: 'cherry' }Collapsing an array of objects into one number. The classic cart or report total.
const products = [
{ price: 10 },
{ price: 20 },
{ price: 30 }
];
const total = products.reduce((acc, item) => acc + item.price, 0);
console.log(total); // 60The initial value and empty arrays
If initialValue is omitted, the first element becomes the accumulator on the first iteration and the walk starts from the second element.
const arr = [1, 2, 3];
const sum = arr.reduce((acc, num) => acc + num);
console.log(sum); // 6Here acc is 1 on the first iteration (the first element), and currentValue is 2, then 3.
If the array is empty and there is no initial value, the method throws:
[].reduce((acc, x) => acc + x); // TypeError: Reduce of empty array with no initial valueThat is exactly why you should always pass an initial value, especially when the array comes from the network and may turn out to be empty.
When to use reduce() and when to use other methods
| Goal | Is reduce() a good fit |
|---|---|
| Sum or product of numbers | Yes |
| Counting or computing statistics | Yes |
| Turning an array into an object | Yes |
| Concatenating strings or arrays | Yes |
| Transforming every element | No, use map() |
| Selecting elements | No, use filter() |
A comparison with the neighbouring iteration methods:
| Method | What it does | What it returns | Can it break the loop |
|---|---|---|---|
forEach() | iterates over elements | undefined | no |
map() | transforms elements | a new array | no |
filter() | selects elements | a new array | no |
find() | finds the first matching element | the element or undefined | yes |
reduce() | folds the whole array into one value | any type: number, string, object | yes, through logic in the callback |
A formula worth memorising: arr.reduce((acc, elem) => newValue, initialValue).
Common mistakes
1. A missing return in the callback body. Curly braces cancel the arrow function's implicit return, so the accumulator becomes undefined.
arr.reduce((acc, num) => { acc + num }, 0); // undefinedThe fix:
arr.reduce((acc, num) => { return acc + num }, 0);2. A mismatched type for the initial value. If the elements are strings and the accumulator is a number, you get concatenation instead of addition.
['1', '2', '3'].reduce((acc, n) => acc + n, 0); // '0123', a stringThe fix, with an explicit conversion:
['1', '2', '3'].reduce((acc, n) => acc + Number(n), 0); // 63. Mutating outside data. An object accumulator may be mutated because it was created inside the call, but mutating the source elements is a bad idea: it makes the result unpredictable.
4. Using reduce() where map() or filter() would do. Such code reads worse than a chain of simple methods and buys you nothing.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.