reduce(): Folding to One Value

JavaScript ES6+ · ✓ verified by execution on

The reduce() method of Array instances executes a user-supplied “reducer” callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single accumulated value.

This method is arguably one of the most powerful functions in the Array prototype because you can technically build any other array method (map, filter, find) just using reduce. Whenever you have an array of data and you need to transform it into a single primitive value, an object, or even a completely new array structure, reduce is the tool you reach for.

javascript
const arr = [1, 2, 3];
const sum = arr.reduce((acc, val) => acc + val, 0);
console.log(sum);
Output
6

The Accumulator and the Initial Value

The core mechanic of reduce relies on the “accumulator” (often abbreviated as acc). This accumulator acts as a running total or a state container that persists across each iteration. The callback function you provide is responsible for taking the current accumulator, applying the current element of the array to it, and explicitly returning the new accumulator for the next loop.

To kick off the process, you should almost always provide an initial value. If supplied, this initial value is used in its place as the first value of the accumulator. It’s best practice to always provide an explicit initial value because it forces you to think about what type of data you are trying to fold the array into. For example, if you are summing numbers, start with 0. If you are building an object, start with {}.

javascript
const arr = [1, 2, 3];
const sum = arr.reduce((acc, val) => acc + val, 10);
console.log(sum);
Output
16

What if we forget the initial value entirely? If no initialValue is provided, the first element in the array will be used as the initial accumulator value and skipped as currentValue. This might seem like a neat shortcut for simple math like addition, but it can quickly lead to unexpected type coercions if your array contains objects or if the first element isn’t of the same type as your expected result. It’s often safer to just type the extra comma and zero.

javascript
const arr = [10, 20, 30];
const sum = arr.reduce((acc, val) => acc + val);
console.log(sum);
Output
60

Edge Cases with Empty Arrays

When you rely on the “skip the initial value” trick, you expose yourself to a dangerous edge case. Calling reduce() on an empty array without an initialValue will immediately throw a TypeError. Because there is no first element to use as the accumulator, JavaScript panics. Always providing an initial value completely prevents this runtime crash, ensuring your application remains resilient even when fed empty datasets.

javascript
const arr = [];
arr.reduce((acc, val) => acc + val);
This example raises an error (on purpose)
TypeError

Visualizing State

To truly grasp how the accumulator morphs step-by-step, we can step through the execution visually. Watch how acc holds the intermediate sum and gets replaced on each tick.

javascript · visualize
const arr = [1, 2, 3];
const sum = arr.reduce((acc, val) => acc + val, 0);
console.log(sum);

Common Misconceptions: The Missing Return

The absolute most common error beginners make when first learning reduce is forgetting to return the accumulator for the next loop. If your callback function doesn’t execute a return statement, it implicitly returns undefined. On the very next iteration, your accumulator will be undefined, which usually causes your code to blow up with a TypeError when you try to call .push() on it or perform arithmetic.

Predict the output javascript

Read the code. What exactly will it print? Commit to an answer before you look.

const arr = [1, 2, 3];
const sum = arr.reduce((acc, val) => {
  acc + val;
}, 0);
console.log(sum);
Output
undefined

Beyond Numbers: Complex Reductions

While summing numbers is the classic example, reduce() can return any type of value: objects, arrays, strings, or even promises, making it unusually versatile. For example, you can use it to aggregate data by counting occurrences of items and folding them into an object dictionary. The pattern is always the same: update the accumulator, then return it.

javascript
const fruits = ['apple', 'banana', 'apple'];
const count = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});
console.log(count.apple);
Output
2
1 2 3 acc: 0 acc: 1 acc: 3 acc: 6 + + + The accumulator (acc) folds the array element-by-element into a single value
reduce() folds an array into a single value: the accumulator starts at its initial value and carries forward through each element, here summing 1, 2 and 3 to reach 6.

Check yourself

What does the reduce() method return?

Reveal answer

A single accumulated value. — The final result of running the reducer across all elements of the array is a single value.

What happens if you do not provide an initial value to reduce()?

Reveal answer

The first element of the array becomes the initial accumulator and is skipped in the iteration. — If no initialValue is provided, the first element in the array will be used as the initial accumulator value and skipped as currentValue.

What happens if you call reduce() on an empty array without an initial value?

Reveal answer

It throws a TypeError. — Calling reduce() on an empty array without an initialValue will throw a TypeError.

Challenges

Challenge 1 +20 XP

Use reduce() to find the longest word in the array. If there is a tie, return the first one.

javascript
  • Test 1 — expects "banana\n"
Need a hint? (−25% XP)

Compare the length of the current word with the accumulator.

Show solution (0 XP)
const words = ['apple', 'banana', 'cherry', 'date'];
const longest = words.reduce((acc, word) => {
  return word.length > acc.length ? word : acc;
}, '');
console.log(longest);

🐞 Bug Hunt +30 XP

This code tries to group an array of numbers into evens and odds, but it's throwing an error or producing undefined! Fix the bug.

This code runs. It just does the wrong thing. Read it, find the defect, fix it — the tests below decide when you are right.

javascript
  • Test 1 — expects "2\n"
Need a hint? (−25% XP)

What is the reducer callback returning? If it returns nothing, what is `acc` on the next loop?

Show solution (0 XP)
const nums = [1, 2, 3, 4];
const grouped = nums.reduce((acc, num) => {
  if (num % 2 === 0) {
    acc.evens.push(num);
  } else {
    acc.odds.push(num);
  }
  return acc;
}, { evens: [], odds: [] });
console.log(grouped.evens.length);