What does the second argument to Array.prototype.reduce do, and what happens if you omit it?
answer
- the seed is the accumulator
- no seed means start at index one
- empty array plus no seed
- single element skips the callback entirely
- seed fixes the accumulator's type
basics
~20 sThe second argument is the initial accumulator value. Supply it and the callback runs once per element starting at index 0. Omit it and the first element becomes the accumulator, iteration starts at index 1, and an empty array throws a TypeError.
solid answer
~40 s`reduce` folds an array into a single value by threading an accumulator through a callback called as `(accumulator, element, index, array)`. The optional second argument seeds that accumulator. With a seed, the callback runs exactly `length` times, starting with `(seed, arr[0], 0)`. Without one, `reduce` takes `arr[0]` as the initial accumulator and starts at index 1, so it runs `length - 1` times — and on an empty array it throws `TypeError: Reduce of empty array with no initial value`. A one-element array with no seed returns that element without ever calling the callback. That is why you should almost always pass an explicit initial value: it makes empty input safe, and it lets the accumulator have a different type from the elements, such as folding objects into a count map.
code
javascript · 11 linesconst rows = [];
try {
console.log(rows.reduce((a, b) => a + b));
} catch (e) {
console.log(e.constructor.name); // 'TypeError'
}
console.log(rows.reduce((a, b) => a + b, 0)); // 0
console.log([42].reduce((a, b) => a * 2)); // 42 — callback never runs
console.log(['a','bb'].reduce((t, w) => t + w.length, 0)); // 3go deeper
Know that reduce turns an array into one value and that the second argument is the starting value. Be able to write a sum with an explicit 0 seed and say why the seed is there.
Explain the call mechanics: with a seed the callback runs length times from index 0, without one it runs length minus one times from index 1, and an empty array with no seed throws a TypeError. Mention reduceRight's mirrored rules.
Demonstrate the production instinct: always seed so a filtered-to-empty input cannot throw, and choose the seed type deliberately so the fold cannot silently produce a concatenated string instead of a number.
Take a position on where folds belong in the codebase — which aggregations are worth expressing as reduce versus a named helper or a loop — and make total, empty-safe functions the convention rather than a case-by-case choice.
## The signature `Array.prototype.reduce(callback, initialValue?)` collapses ("folds") an array into a single value. The callback receives four arguments: `(accumulator, currentValue, currentIndex, array)`. Whatever the callback returns becomes the accumulator for the next iteration, and the last returned accumulator is `reduce`'s result. `reduce` itself never mutates the source array. ```js [1, 2, 3, 4].reduce((acc, n) => acc + n, 0); // 10 ``` ## With an initial value When you pass `initialValue`, it *is* the accumulator on the first call and iteration begins at index 0. The callback therefore runs exactly once per element: ```js [1, 2, 3].reduce((acc, n) => { console.log(acc, n); return acc + n; }, 10); // logs: 10 1 / 11 2 / 13 3 → result 16 ``` The seed also fixes the accumulator's **type**. That is what lets `reduce` do things `map` and `filter` cannot: fold an array of objects into a number, a string, an object, a `Map`, or a `Set`. ## Without an initial value Omit it and `reduce` uses the array's first element as the starting accumulator and begins iteration at index 1 — one fewer callback invocation: ```js [1, 2, 3].reduce((acc, n) => { console.log(acc, n); return acc + n; }); // logs: 1 2 / 3 3 → result 6 ``` Two consequences follow, and interviewers probe both. **The empty-array throw.** With no seed and no elements there is nothing to start from, so the spec makes it a hard error rather than returning `undefined`: ```js [].reduce((a, b) => a + b); // TypeError: Reduce of empty array with no initial value [].reduce((a, b) => a + b, 0); // 0 ``` This is the classic production bug: the sum works all through development and blows up the first time a filter upstream returns nothing. **The zero-call case.** A single-element array with no seed returns that element directly, without calling the callback at all: ```js ['only'].reduce((a, b) => a + b); // 'only' — callback never runs [42].reduce((a, b) => a * 2); // 42, not 84 ``` So a callback with a side effect or a validation cannot be relied on to run for every element when the seed is missing. ## Type consistency Without a seed the accumulator starts out as an element, which pushes the fold's result toward the element type — fine for summing numbers, wrong for anything else: ```js const words = ['a', 'bb', 'ccc']; words.reduce((total, w) => total + w.length, 0); // 6 — seed makes it a number words.reduce((total, w) => total + w.length); // 'a23' — starts as the string 'a' ``` The second line does not throw; it silently produces a string via `+` concatenation. Bugs of this shape are the strongest argument for always passing the seed. ## reduceRight `Array.prototype.reduceRight` is the same fold walking from the last index toward the first, with identical initial-value rules (omit it and the *last* element seeds the accumulator; an empty array with no seed throws the same `TypeError`). It matters when the operation is not associative or when order is part of the meaning: ```js ['a', 'b', 'c'].reduce((acc, x) => acc + x); // 'abc' ['a', 'b', 'c'].reduceRight((acc, x) => acc + x); // 'cba' ``` A common use is right-to-left function composition, where `reduceRight` expresses `f(g(h(x)))` naturally. ## Practical rule Always pass an explicit initial value unless you deliberately want first-element seeding — and if you do want it, guard the empty case first. The seed documents the accumulator's type, makes the fold total (defined for every input including `[]`), and guarantees the callback runs once per element.
- How many times does the callback run with and without an initial value?With a seed it runs exactly `array.length` times, once per element starting at index 0. Without a seed it runs `array.length - 1` times, because the first element is consumed as the starting accumulator and iteration begins at index 1. For a one-element array with no seed it runs zero times and that element is returned as-is.
- How is reduceRight different, and when would you reach for it?`reduceRight` folds from the last element to the first with the same initial-value rules — no seed means the last element starts the accumulator. Direction only matters for non-associative operations: string concatenation, subtraction, or building right-to-left function composition where `compose(f, g, h)(x)` must evaluate `h` first.
- Can reduce express map and filter, and should it?Yes — `map` is a reduce that pushes a transformed value onto an array accumulator, and `filter` is a reduce that pushes conditionally. Interviewers ask it to test that you understand accumulators. In real code, prefer the named method: a reader recognises `map` instantly, while a reduce that rebuilds an array hides its intent behind boilerplate.
saying these in an interview costs you the question
- Says reduce on an empty array returns undefined
- Thinks the callback always runs once per element
- Believes the accumulator must be the same type as the elements
- Claims omitting the seed just defaults it to zero
- Forgets to return the accumulator from the callback