Cette page a été traduite à partir de l'anglais par la communauté.Vous pouvez contribuer en rejoignant la communauté francophone sur MDN Web Docs.
Array : méthode reduce()
Baseline Widely available
Cette fonctionnalité est bien établie et fonctionne sur de nombreux appareils et versions de navigateurs. Elle est disponible sur tous les navigateurs depuis juillet 2015.
La méthodereduce() des instancesArray exécute une fonction de rappel « de réduction » fournie par l'utilisateur·ice sur chaque élément du tableau, dans l'ordre, en transmettant la valeur retournée par le calcul précédent. Le résultat final de l'exécution du réducteur sur tous les éléments du tableau est une seule valeur.
La première fois que la fonction de rappel est exécutée, il n'y a pas de « valeur retournée par le calcul précédent ». Si elle est fournie, une valeur initiale peut être utilisée à la place. Sinon, l'élément du tableau d'index 0 est utilisé comme valeur initiale et l'itération commence à l'élément suivant (index 1 au lieu de l'index 0).
Dans cet article
Exemple interactif
const array1 = [1, 2, 3, 4];// 0 + 1 + 2 + 3 + 4const initialValue = 0;const sumWithInitial = array1.reduce( (accumulator, currentValue) => accumulator + currentValue, initialValue,);console.log(sumWithInitial);// Résultat attendu : 10Syntaxe
reduce(callbackFn)reduce(callbackFn, initialValue)Paramètres
callbackFnLa fonction de rappel à exécuter pour chaque élément du tableau. Sa valeur de retour devient la valeur du paramètre
accumulatorlors de l'appel suivant decallbackFn. Pour le dernier appel, la valeur de retour devient la valeur retournée parreduce(). La fonction est appelée avec les arguments suivants :accumulatorLa valeur résultant de l'appel précédent de
callbackFn. Lors du premier appel, sa valeur estinitialValuesi ce dernier est défini ; sinon, sa valeur estarray[0].currentValueLa valeur de l'élément courant. Lors du premier appel, sa valeur est
array[0]siinitialValueest défini ; sinon, sa valeur estarray[1].currentIndexL'index de
currentValuedans le tableau. Lors du premier appel, sa valeur est0siinitialValueest défini ; sinon1.arrayLe tableau sur lequel
reduce()a été appelé.
initialValueFacultatifLa valeur à laquelle
accumulatorest initialisé lors du premier appel de la fonction de rappel.SiinitialValueest défini,callbackFncommence à s'exécuter avec la première valeur du tableau commecurrentValue.SiinitialValuen'est pas défini,accumulatorest initialisé à la première valeur du tableau, etcallbackFncommence à s'exécuter avec la seconde valeur du tableau commecurrentValue. Dans ce cas, si le tableau est vide (et qu'il n'y a donc pas de première valeur à retourner commeaccumulator), une erreur est levée.
Valeur de retour
La valeur qui résulte de l'exécution de la fonction de rappel « de réduction » sur l'ensemble du tableau jusqu'à la fin.
Exceptions
TypeErrorLevée si le tableau ne contient aucun élément et que la valeur initiale n'est pas définie.
Description
La méthodereduce() est uneméthode itérative. Elle exécute une fonction de rappel « de réduction » sur tous les éléments du tableau, dans l'ordre croissant des indices, et les accumule en une seule valeur. À chaque itération, la valeur retournée parcallbackFn est transmise à nouveau àcallbackFn lors de l'appel suivant en tant qu'accumulator. La dernière valeur deaccumulator (c'est-à-dire la valeur retournée parcallbackFn lors de la dernière itération du tableau) devient la valeur retournée parreduce(). Consultez la sectionméthodes itératives pour plus d'informations sur le fonctionnement général de ces méthodes.
callbackFn n'est appelée que pour les indices du tableau qui ont des valeurs attribuées. Elle n'est pas appelée pour les cases vides dans untableau creux.
Contrairement aux autresméthodes itératives,reduce() n'accepte pas d'argumentthisArg.callbackFn est toujours appelée avec la valeurundefined pourthis, qui est remplacée parglobalThis sicallbackFn n'est pas en mode strict.
reduce() est un concept central de laprogrammation fonctionnelle : il n'est pas possible d'y modifier une valeur, donc pour accumuler toutes les valeurs d'un tableau, il faut retourner une nouvelle valeur d'accumulateur à chaque itération. Cette convention s'applique àreduce() en JavaScript : il convient d'utiliserl'opérateur de propagation ou d'autres méthodes de copie pour créer de nouveaux tableaux et objets comme accumulateur, plutôt que de modifier l'existant. Si vous décidez de modifier l'accumulateur au lieu de le copier, veillez à toujours retourner l'objet modifié dans la fonction de rappel, sinon l'itération suivante recevra la valeurundefined. Cependant, copier l'accumulateur peut entraîner une utilisation accrue de la mémoire et une dégradation des performances : voirQuand ne pas utiliser reduce() pour plus de détails. Dans ces cas, pour éviter de mauvaises performances et un code illisible, il est préférable d'utiliser une bouclefor à la place.
La méthodereduce() estgénérique. Elle attend seulement que la valeur dethis possède une propriétélength et des propriétés à clés entières.
Cas particuliers
Si le tableau ne contient qu'un seul élément (peu importe sa position) et qu'aucuneinitialValue n'est fournie, ou siinitialValue est fournie mais que le tableau est vide, la valeur unique sera retournéesans appelercallbackFn.
SiinitialValue est fournie et que le tableau n'est pas vide, la méthode reduce appellera toujours la fonction de rappel en commençant à l'index 0.
SiinitialValue n'est pas fournie, la méthode reduce se comporte différemment selon que la longueur du tableau est supérieure à 1, égale à 1 ou égale à 0, comme illustré dans l'exemple suivant :
const getMax = (a, b) => Math.max(a, b);// la fonction de rappel est appelée pour chaque élément du tableau à partir de l'index 0[1, 100].reduce(getMax, 50); // 100[50].reduce(getMax, 10); // 50// la fonction de rappel est appelée une fois pour l'élément à l'index 1[1, 100].reduce(getMax); // 100// la fonction de rappel n'est pas appelée[50].reduce(getMax); // 50[].reduce(getMax, 1); // 1[].reduce(getMax); // TypeErrorExemples
>Fonctionnement dereduce() sans valeur initiale
Le code ci-dessous montre ce qu'il se passe si l'on appellereduce() avec un tableau et sans valeur initiale.
const array = [15, 16, 17, 18, 19];function reducer(accumulator, currentValue, index) { const returns = accumulator + currentValue; console.log( `accumulator: ${accumulator}, currentValue: ${currentValue}, index: ${index}, returns: ${returns}`, ); return returns;}array.reduce(reducer);La fonction de rappel sera appelée quatre fois, avec les arguments et valeurs de retour suivants à chaque appel :
accumulator | currentValue | index | Valeur retournée | |
|---|---|---|---|---|
| Premier appel | 15 | 16 | 1 | 31 |
| Deuxième appel | 31 | 17 | 2 | 48 |
| Troisième appel | 48 | 18 | 3 | 66 |
| Quatrième appel | 66 | 19 | 4 | 85 |
Le paramètrearray ne change jamais pendant le processus : il reste toujours[15, 16, 17, 18, 19]. La valeur retournée parreduce() sera celle du dernier appel de la fonction de rappel (85).
Fonctionnement dereduce() avec une valeur initiale
Ici, on réduit le même tableau avec le même algorithme, mais en passant uneinitialValue de10 comme second argument àreduce() :
[15, 16, 17, 18, 19].reduce( (accumulator, currentValue) => accumulator + currentValue, 10,);La fonction de rappel sera appelée cinq fois, avec les arguments et valeurs de retour suivants à chaque appel :
accumulator | currentValue | index | Valeur retournée | |
|---|---|---|---|---|
| Premier appel | 10 | 15 | 0 | 25 |
| Deuxième appel | 25 | 16 | 1 | 41 |
| Troisième appel | 41 | 17 | 2 | 58 |
| Quatrième appel | 58 | 18 | 3 | 76 |
| Cinquième appel | 76 | 19 | 4 | 95 |
La valeur retournée parreduce() dans ce cas sera95.
Additionner les valeurs d'un tableau d'objets
Pour additionner les valeurs contenues dans un tableau d'objets, ilfaut fournir uneinitialValue afin que chaque élément soit traité par la fonction.
const objects = [{ x: 1 }, { x: 2 }, { x: 3 }];const sum = objects.reduce( (accumulator, currentValue) => accumulator + currentValue.x, 0,);console.log(sum); // 6Chaînage séquentiel de fonctions
La fonctionpipe prend une séquence de fonctions et retourne une nouvelle fonction. Lorsque cette nouvelle fonction est appelée avec un argument, la séquence de fonctions est appelée dans l'ordre, chacune recevant la valeur retournée par la fonction précédente.
const pipe = (...functions) => (initialValue) => functions.reduce((acc, fn) => fn(acc), initialValue);// Briques de base pour la compositionconst double = (x) => 2 * x;const triple = (x) => 3 * x;const quadruple = (x) => 4 * x;// Fonctions composées pour multiplier par des valeurs spécifiquesconst multiply6 = pipe(double, triple);const multiply9 = pipe(triple, triple);const multiply16 = pipe(quadruple, quadruple);const multiply24 = pipe(double, triple, quadruple);// Utilisationmultiply6(6); // 36multiply9(9); // 81multiply16(16); // 256multiply24(10); // 240Exécuter des promesses en séquence
Lechaînage de promesses est essentiellement un chaînage de fonctions comme démontré dans la section précédente, mais réalisé de façon asynchrone.
// À comparer avec pipe : fn(acc) devient acc.then(fn),// et initialValue est garanti d'être une promesseconst asyncPipe = (...functions) => (initialValue) => functions.reduce((acc, fn) => acc.then(fn), Promise.resolve(initialValue));// Briques de base pour la compositionconst p1 = async (a) => a * 5;const p2 = async (a) => a * 2;// Les fonctions composées peuvent aussi retourner des non-promesses, car les valeurs sont// toutes enveloppées dans des promesses au finalconst f3 = (a) => a * 3;const p4 = async (a) => a * 4;asyncPipe(p1, p2, f3, p4)(10).then(console.log); // 1200asyncPipe peut aussi être implémenté avecasync/await, ce qui montre mieux sa similarité avecpipe :
const asyncPipe = (...functions) => (initialValue) => functions.reduce(async (acc, fn) => fn(await acc), initialValue);Utiliserreduce() avec des tableaux creux
reduce() ignore les éléments manquants dans les tableaux creux, mais n'ignore pas les valeursundefined.
console.log([1, 2, , 4].reduce((a, b) => a + b)); // 7console.log([1, 2, undefined, 4].reduce((a, b) => a + b)); // NaNAppelerreduce() sur des objets ressemblant à des tableaux
La méthodereduce() lit la propriétélength dethis puis accède à chaque propriété dont la clé est un entier non négatif inférieur àlength.
const objetSimilaireTableau = { length: 3, 0: 2, 1: 3, 2: 4, 3: 99, // ignoré par reduce() car length vaut 3};console.log( Array.prototype.reduce.call(objetSimilaireTableau, (x, y) => x + y),);// 9Quand ne pas utiliserreduce()
Les fonctions d'ordre supérieur polyvalentes commereduce() peuvent être puissantes mais parfois difficiles à comprendre, surtout pour les développeur·euse·s JavaScript moins expérimenté·e·s. Si le code est plus clair avec d'autres méthodes de tableau, il faut peser la lisibilité face aux autres avantages dereduce().
Notez quereduce() est toujours équivalent à une bouclefor...of, sauf qu'au lieu de modifier une variable dans la portée supérieure, on retourne la nouvelle valeur à chaque itération :
const val = array.reduce((acc, cur) => update(acc, cur), initialValue);// Équivalent à :let val = initialValue;for (const cur of array) { val = update(val, cur);}Comme indiqué précédemment, la raison pour laquelle on peut vouloir utiliserreduce() est d'imiter les pratiques de programmation fonctionnelle avec des données immuables. Ainsi, les développeur·euse·s qui respectent l'immuabilité de l'accumulateur copient souvent tout l'accumulateur à chaque itération, comme ceci :
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];const countedNames = names.reduce((allNames, name) => { const currCount = Object.hasOwn(allNames, name) ? allNames[name] : 0; return { ...allNames, [name]: currCount + 1, };}, {});Ce code est inefficace, car chaque itération doit copier tout l'objetallNames, qui peut être volumineux selon le nombre de noms uniques. Ce code a une complexité dans le pire des cas enO(N^2), oùN est la longueur denames.
Une meilleure alternative consiste àmuter l'objetallNames à chaque itération. Cependant, siallNames est de toute façon modifié, il peut être préférable de convertir lereduce() en bouclefor, ce qui est bien plus lisible :
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];const countedNames = names.reduce((allNames, name) => { const currCount = allNames[name] ?? 0; allNames[name] = currCount + 1; // retourner allNames, sinon l'itération suivante reçoit undefined return allNames;}, Object.create(null));const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];const countedNames = Object.create(null);for (const name of names) { const currCount = countedNames[name] ?? 0; countedNames[name] = currCount + 1;}Ainsi, si votre accumulateur est un tableau ou un objet et que vous le copiez à chaque itération, vous pouvez accidentellement introduire une complexité quadratique dans votre code, ce qui dégradera rapidement les performances sur de grandes données. Cela s'est produit dans du code réel : voir par exempleRendre Tanstack Table 1000x plus rapide avec un changement d'une ligne(angl.).
Quelques cas d'usage acceptables dereduce() sont donnés ci-dessus (notamment la somme d'un tableau, le chaînage de promesses et le chaînage de fonctions). Il existe d'autres cas où de meilleures alternatives àreduce() existent.
Aplatir un tableau de tableaux. Utilisez plutôt
flat().jsconst flattened = array.reduce((acc, cur) => acc.concat(cur), []);jsconst flattened = array.flat();Regrouper des objets selon une propriété. Utilisez plutôt
Object.groupBy().jsconst groups = array.reduce((acc, obj) => { const key = obj.name; const curGroup = acc[key] ?? []; return { ...acc, [key]: [...curGroup, obj] };}, {});jsconst groups = Object.groupBy(array, (obj) => obj.name);Concaténer des tableaux contenus dans un tableau d'objets. Utilisez plutôt
flatMap().jsconst friends = [ { name: "Anna", books: ["Bible", "Harry Potter"] }, { name: "Bob", books: ["Guerre et Paix", "Roméo et Juliette"] }, { name: "Alice", books: ["Le Seigneur des anneaux", "Shining"] },];const allBooks = friends.reduce((acc, cur) => [...acc, ...cur.books], []);jsconst allBooks = friends.flatMap((person) => person.books);Retirer les doublons d'un tableau. Utilisez plutôt
SetetArray.from().jsconst uniqArray = array.reduce( (acc, cur) => (acc.includes(cur) ? acc : [...acc, cur]), [],);jsconst uniqArray = Array.from(new Set(array));Éliminer ou ajouter des éléments dans un tableau. Utilisez plutôt
flatMap().js// Prend un tableau de nombres et sépare les carrés parfaits en leurs racines carréesconst roots = array.reduce((acc, cur) => { if (cur < 0) return acc; const root = Math.sqrt(cur); if (Number.isInteger(root)) return [...acc, root, root]; return [...acc, cur];}, []);jsconst roots = array.flatMap((val) => { if (val < 0) return []; const root = Math.sqrt(val); if (Number.isInteger(root)) return [root, root]; return [val];});Si vous ne faites qu'éliminer des éléments d'un tableau, vous pouvez aussi utiliser
filter().Rechercher des éléments ou tester si des éléments satisfont une condition. Utilisez plutôt
find()etfindIndex()ousome()etevery(). Ces méthodes ont l'avantage supplémentaire de retourner le résultat dès qu'il est certain, sans parcourir tout le tableau.jsconst allEven = array.reduce((acc, cur) => acc && cur % 2 === 0, true);jsconst allEven = array.every((val) => val % 2 === 0);
Dans les cas oùreduce() est le meilleur choix, une bonne documentation et des noms de variables sémantiques peuvent aider à atténuer les problèmes de lisibilité.
Spécifications
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-array.prototype.reduce> |
Compatibilité des navigateurs
Voir aussi
- Guide des collections indexées
- L'objet global
Array - La méthode
Array.prototype.map() - La méthode
Array.prototype.flat() - La méthode
Array.prototype.flatMap() - La méthode
Array.prototype.reduceRight() - La méthode
TypedArray.prototype.reduce() - La méthode
Object.groupBy() - La méthode
Map.groupBy() - Prothèse d'émulation de
Array.prototype.reducedanscore-js(angl.) - Prothèse d'émulation es-shims de
Array.prototype.reduce(angl.)