Additionner des montants, compter des occurrences, regrouper des lignes par pays : trois opérations différentes qui partagent la même forme, un tableau en entrée et une seule valeur en sortie.
reduce est la méthode qui décrit cette forme, et la plus redoutée du lot parce qu'elle demande de nommer deux choses au lieu d'une.
Définition
reduce parcourt un Array (tableau) en transportant une valeur d'un tour à l'autre, l'accumulateur. À chaque élément, la fonction reçoit cet accumulateur et l'élément, et renvoie le nouvel accumulateur. Le dernier renvoyé est le résultat.
const montants = [12, 30, 8];
const total = montants.reduce((somme, m) => somme + m, 0);
console.log(total); // 50Le 0 final est la valeur de départ de l'accumulateur, souvent prise pour un détail. Elle décide en réalité du type du résultat : 0 pour un nombre, "" pour une chaîne, {} pour un objet, [] pour un tableau.
La valeur initiale n'est pas facultative
Elle peut être omise, et le premier élément sert alors d'accumulateur. Sur un tableau vide, il n'y a plus rien à prendre.
try {
[].reduce((a, b) => a + b);
} catch (err) {
console.log(err.name); // TypeError
console.log(err.message); // Reduce of empty array with no initial value
}
console.log([].reduce((a, b) => a + b, 0)); // 0Le tableau vide n'est pas un cas rare : c'est ce que rend un Array.filter() qui n'a rien trouvé, ou une requête sans résultat. Écrire la valeur initiale coûte trois caractères et supprime la panne.
Regrouper des données
C'est l'usage où reduce devance nettement une boucle, parce que la structure de sortie est déclarée à la fin de la ligne.
const ventes = [
{ pays: "FR", montant: 40 },
{ pays: "BE", montant: 15 },
{ pays: "FR", montant: 60 },
];
const parPays = ventes.reduce((acc, v) => {
acc[v.pays] = (acc[v.pays] ?? 0) + v.montant;
return acc;
}, {});
console.log(parPays); // { FR: 100, BE: 15 }Ne recréez pas l'accumulateur à chaque tour avec Spread (...), comme dans reduce((acc, v) => ({ ...acc, [v.pays]: v.montant }), {}). Le coût devient proportionnel au carré du nombre d'éléments, et la ligne se lit à peine mieux. Modifiez l'accumulateur puis renvoyez-le.
Questions fréquentes
Quand faut-il préférer une boucle ?
Dès que la fonction dépasse cinq ou six lignes, ou qu'elle doit s'arrêter avant la fin. reduce parcourt toujours tout le tableau, sans échappatoire. Une boucle for avec un break dit alors la même chose plus clairement.
reduce peut-il remplacer Array.map() et filter ?
Techniquement oui, en un seul parcours. En pratique le gain de vitesse est faible et le code devient nettement moins lisible : le nom map annonce une transformation, un reduce n'annonce rien. Gardez-le pour ce que les autres ne font pas.
À quoi sert reduceRight ?
À parcourir le tableau de la fin vers le début, avec la même signature. Le cas réel est la composition de fonctions, où l'ordre d'application compte. Pour une somme ou un comptage, le sens de parcours ne change rien au résultat.