Array.prototype.reduce() reduziert ein Array zu einem einzigen Wert — eine Summe, ein aggregiertes Objekt, ein neues Array. Der Callback bekommt einen Akkumulator und das aktuelle Element und liefert den neuen Akkumulator-Wert. Mit Initial-Wert ist das Verhalten klar und sicher; ohne Initial-Wert wird das erste Element als Start genommen — bei leerem Array gibt es einen TypeError. reduce ist eine der mächtigsten, aber auch eine der häufigst überstrapazierten Methoden — für viele Anwendungen ist eine spezifischere Methode lesbarer.

Signatur & Grundform

JavaScript signatur.js
arr.reduce(
    callback: (acc: U, el: T, i: number, arr: T[]) => U,
    initialValue?: U
): U
JavaScript grundform.js
const zahlen = [1, 2, 3, 4, 5];

// Summe — der Klassiker
const summe = zahlen.reduce((acc, n) => acc + n, 0);
console.log(summe);          // 15

// Produkt
const produkt = zahlen.reduce((acc, n) => acc * n, 1);
console.log(produkt);        // 120
Output
15
120

acc ist der Akkumulator, der von einer Iteration zur nächsten weitergereicht wird. Der Initial-Wert (0, 1, [], {} etc.) bestimmt den Startwert und den Typ des Ergebnisses.

Initial-Wert — fast immer setzen

Ohne Initial-Wert nimmt reduce das erste Element als Start. Das kann sinnvoll sein (z.B. bei Summe), führt aber bei leerem Array zu TypeError.

JavaScript ohne-init.js
const arr = [1, 2, 3];

// Mit Initial: sicher
console.log(arr.reduce((a, b) => a + b, 0));     // 6

// Ohne Initial: erstes Element wird Start
console.log(arr.reduce((a, b) => a + b));        // 6

// ABER: leeres Array ohne Initial → TypeError
try {
    [].reduce((a, b) => a + b);
} catch (e) {
    console.log('Fehler:', e.message);
}

// Mit Initial: immer sicher
console.log([].reduce((a, b) => a + b, 0));      // 0
Output
6
6
Fehler: Reduce of empty array with no initial value
0

Faustregel: immer einen Initial-Wert übergeben. Macht den Code expliziter und sicher gegen leere Inputs.

Group-By — Klassisches Beispiel

Vor ES2024 war reduce der Standard-Weg, ein Array zu gruppieren. Heute gibt es Object.groupBy direkt.

JavaScript groupby.js
const items = [
    { kategorie: 'frucht', name: 'Apfel' },
    { kategorie: 'gemuese', name: 'Karotte' },
    { kategorie: 'frucht', name: 'Birne' },
    { kategorie: 'gemuese', name: 'Salat' },
];

// Pre-ES2024: mit reduce
const gruppen = items.reduce((acc, item) => {
    const key = item.kategorie;
    if (!acc[key]) acc[key] = [];
    acc[key].push(item.name);
    return acc;
}, {});
console.log(gruppen);

// ES2024: Object.groupBy — direkt
const gruppen2 = Object.groupBy(items, item => item.kategorie);
console.log(Object.keys(gruppen2));
Output
{ frucht: [ 'Apfel', 'Birne' ], gemuese: [ 'Karotte', 'Salat' ] }
[ 'frucht', 'gemuese' ]

In neuem Code: Object.groupBy nutzen. reduce-Version bleibt in Legacy-Code reichlich.

Statistik in einem Pass

Multiple Aggregationen lassen sich in einem reduce kombinieren — effizienter als mehrere separate map/filter-Durchläufe.

JavaScript statistik.js
const punkte = [85, 92, 78, 95, 88];

const stats = punkte.reduce(
    (acc, p) => ({
        summe: acc.summe + p,
        min: Math.min(acc.min, p),
        max: Math.max(acc.max, p),
        anzahl: acc.anzahl + 1,
    }),
    { summe: 0, min: Infinity, max: -Infinity, anzahl: 0 }
);

const durchschnitt = stats.summe / stats.anzahl;
console.log({ ...stats, durchschnitt });
Output
{
  summe: 438,
  min: 78,
  max: 95,
  anzahl: 5,
  durchschnitt: 87.6
}

reduce als kombinierter map + filter

Wenn man arr.filter(p).map(f) in einer einzigen Iteration ausführen will, ist reduce das Werkzeug.

JavaScript filter-map-in-reduce.js
const items = [1, 2, 3, 4, 5, 6, 7, 8];

// Klassisch: zwei Iterationen
const a = items.filter(n => n % 2 === 0).map(n => n * 10);
console.log(a);              // [20, 40, 60, 80]

// Mit reduce: eine Iteration
const b = items.reduce((acc, n) => {
    if (n % 2 === 0) acc.push(n * 10);
    return acc;
}, []);
console.log(b);              // [20, 40, 60, 80]

// flatMap für eine Iteration mit „leer-zurückgeben-um-zu-filtern":
const c = items.flatMap(n => n % 2 === 0 ? [n * 10] : []);
console.log(c);
Output
[ 20, 40, 60, 80 ]
[ 20, 40, 60, 80 ]
[ 20, 40, 60, 80 ]

Die flatMap-Variante ist oft die lesbarste Form für „filter + map" in einem Pass.

reduceRight — von hinten nach vorn

Das spiegelbildliche Pendant: iteriert von rechts nach links.

JavaScript reduce-right.js
const arr = ['a', 'b', 'c', 'd'];

// Konkatenieren von links
console.log(arr.reduce((acc, x) => acc + x, ''));      // 'abcd'

// Konkatenieren von rechts
console.log(arr.reduceRight((acc, x) => acc + x, '')); // 'dcba'
Output
abcd
dcba

In Praxis selten — meist reicht reduce mit angepasster Logik.

Wann besser nicht reduce?

reduce ist mächtig, aber für viele Use-Cases zu generisch. Spezifischere Methoden sind oft lesbarer:

AufgabeStatt reduce besser
Werte aufsummierenreduce ist hier idiomatisch
Min/Max findenMath.max(...arr), Math.min
GruppierungObject.groupBy (ES2024)
Array in Mapnew Map(arr) direkt
Array invertierenarr.toReversed() / arr.reverse()
Suchen erstes Elementfind
Erfüllen alle/einesevery / some
Flach klopfenarr.flat()

Wer reduce für etwas verwendet, das mit einer dieser spezifischen Methoden klarer wäre — schreibt absichtlich „smart code" auf Kosten der Lesbarkeit.

Async Reduce — sequenziell mit Promise-Chain

reduce ist synchron, eignet sich aber für sequenzielle async-Ketten:

JavaScript async-reduce.js
async function process(x) {
    await new Promise(r => setTimeout(r, 5));
    return x * 2;
}

(async () => {
    const arr = [1, 2, 3];

    // Sequenziell: reduce mit Promise-Akkumulator
    const result = await arr.reduce(async (accP, x) => {
        const acc = await accP;
        acc.push(await process(x));
        return acc;
    }, Promise.resolve([]));

    console.log(result);   // [2, 4, 6]
})();
Output
[ 2, 4, 6 ]

Verständlicher ist meist eine for-of-Schleife mit await — die Promise-Reduce-Pattern braucht es nur, wenn man unbedingt funktional bleiben will.

Besonderheiten

Initial-Wert immer setzen — Sicherheit vor leerem Array

Ohne Initial-Wert wirft reduce bei leerem Array TypeError. Mit Initial-Wert (auch wenn er 0 oder [] ist) ist die Methode immer sicher.

Akkumulator-Typ vs. Element-Typ können verschieden sein

Sehr typisch: arr.reduce((acc, x) => ({ ...acc, [x]: true }), {}) sammelt aus einem Array ein Object. Der TypeScript-Generic reduce<U> reflektiert das.

Spread-Spread in reduce: O(n²) Performance-Falle

arr.reduce((acc, x) => [...acc, transform(x)], []) ist quadratisch — bei jedem Schritt wird das gesamte acc kopiert. Bei großen Arrays: acc.push(...) statt Spread.

reduce ist mächtig — oft überzogen für simple Aggregationen

Für Min/Max: Math.max(...arr). Für Gruppierung: Object.groupBy. Für Konkatenation: arr.join(''). reduce ist die letzte Wahl, wenn keine spezifische Methode passt.

Object.groupBy seit ES2024 ersetzt reduce-Gruppierung

Object.groupBy(arr, x => x.kategorie) ist deklarativer als ein 5-Zeilen-Reduce. Baseline 2024 — Polyfill für ältere Targets verfügbar.

reduceRight in Praxis selten — meist äquivalent zu reduce

Bei kommutativen Operationen (Summe, Max) ergibt reduceRight dasselbe Resultat. Nur bei nicht-kommutativen (Konkatenation, Compose) ist die Reihenfolge relevant.

Pipe und Compose lassen sich mit reduce ausdrücken

const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x); ist eine elegante Eine-Zeilen-Definition für Function-Composition. Das ist eine der seltenen Stellen, an denen reduce wirklich glänzt.

Iterator Helpers (ES2025) — lazy reduce kommt

Iterator.prototype.reduce erlaubt Reduce auf einem unendlichen oder lazy Iterator. Praktisch für Streaming-Pipelines, bei denen das gesamte Array nicht erst materialisiert werden soll.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Arrays

Zur Übersicht