CodeOath
← All posts
JavaScript60 min total · 16 parts

JavaScript Array and Object Methods Cheat Sheet

Part 6 of 16 · ~2 min

reduce(), the Method That Can Build Anything

.reduce() gets a section to itself because, underneath, it's the one method the others here could all theoretically be rebuilt out of — and, not coincidentally, it's usually the one that takes a few genuine uses before it stops feeling like a puzzle.

const totalScore = candidates.reduce((sum, candidate) => sum + candidate.score, 0);
// starts at 0, then: 0+82=82, 82+74=156, 156+91=247, 247+68=315, 315+59=374

That second argument — the 0 — is the initial value, and skipping it is riskier than it looks:

[].reduce((sum, c) => sum + c.score);       // TypeError: Reduce of empty array with no initial value
[].reduce((sum, c) => sum + c.score, 0);    // 0 — safe, because there's an initial value to fall back on

Leave that argument off and .reduce() borrows the array's own first element as its starting point, then folds forward beginning at the second element — a strategy with nothing to borrow from on an empty array, and that's the precise moment it throws instead of quietly producing a wrong answer. A brand-new job posting with zero applicants so far would leave candidates empty, and a .reduce() with no initial value would take down whatever dashboard code called it that day. Always supply one, unless you've already ruled out an empty array.

.reduce() isn't limited to folding down to a number — what it hands back can take any shape you want, including another object entirely:

const byRole = candidates.reduce((groups, candidate) => {
  (groups[candidate.role] ??= []).push(candidate.name);
  return groups;
}, {});
// { backend: ["Priya Shah", "Amara Chen", "Lena Fischer"], frontend: ["Diego Ramos", "Sam Okafor"] }

That ??= is worth pausing on, since it's easy to write past without really registering what it does: groups[candidate.role] ??= [] means "if groups[candidate.role] is currently null or undefined, assign it []; otherwise leave it exactly as it is." It's the nullish-coalescing operator (??, covered fully a few sections down) fused with assignment — shorthand for groups[candidate.role] = groups[candidate.role] ?? []. The first time a role shows up it gets a fresh empty array; every time after that, the existing array is left alone and .push() adds to it.

.reduce() has a mirror: .reduceRight(), identical except it folds from the end of the array toward the start instead of the start toward the end:

const names = candidates.map(c => c.name);

names.reduce((acc, name) => acc + " -> " + name);
// "Priya Shah -> Diego Ramos -> Amara Chen -> Sam Okafor -> Lena Fischer"

names.reduceRight((acc, name) => acc + " -> " + name);
// "Lena Fischer -> Sam Okafor -> Amara Chen -> Diego Ramos -> Priya Shah"

For anything commutative — summing scores, building an unordered lookup — it makes no difference which one you reach for. It matters the moment order does: composing a chain of functions right-to-left, or folding something where later elements need to take priority over earlier ones.