--- title: Array.prototype.reduce() slug: Web/JavaScript/Reference/Global_Objects/Array/Reduce tags: - Array - Array method - ECMAScript 5 - JavaScript - Method - Prototype - Reduce - Referenza translation_of: Web/JavaScript/Reference/Global_Objects/Array/Reduce ---
Il metodo reduce()
esegue una funzione reducer (che tu fornisci) su ogni elemento dell'array, risultante in un unico output.
La funzione reducer accetta quattro argomenti:
Il valore restituito della funzione reducer viene assegnato all'accumulatore, il cui valore viene memorizzato attraverso ogni iterazione nell'intero array e in definitiva, diventa il valore finale finale singolo.
arr.reduce(callback(accumulator, currentValue[, index[, array]]) [, initialValue])
callback
initialValue
), accetta 4 argomenti:
accumulator
initialValue
, se fornito (vedere di seguito).currentValue
index
{{optional_inline}}initialValue
Altrimenti, inizia dall'indice 1.array
{{optional_inline}}reduce()
.initialValue
{{optional_inline}}callback
. Se non viene fornito initialValue
il primo elemento dell'array verrà utilizzato e saltato. Chiamare reduce()
su un array vuoto senza initialValue
genererà un TypeError
.Il singolo valore che risulta dalla riduzione.
Il metodo reduce()
esegue il callback
una volta per ogni valore assegnato presente nell'array, prendendo quattro argomenti:
accumulator
currentValue
currentIndex
array
La prima volta che viene chiamato il callback, accumulator
e currentValue
possono essere uno dei due valori. Se initialValue
viene fornito nella chiamata a reduce()
, accumulator
sarà uguale a initialValue
, e currentValue
sarà uguale al primo valore nell'array. Se non viene fornito alcun valore initialValue
, accumulator
sarà uguale al primo valore dell'array e currentValue
sarà uguale al secondo.
Note: Se non viene fornito initialValue
, reduce()
eseguirà la funzione di callback a partire dall'indice 1, saltando il primo indice. Se viene fornito initialValue
, inizierà dall'indice 0.
Se l'array è vuoto e non viene fornito initialValue
verrà generato un {{jsxref("TypeError")}}. Se l'array ha solo un elemento (indipendentemente dalla posizione) e non viene fornito initialValue
, o se è fornito initialValue
ma l'array è vuoto, il valore solo verrà restituito senza chiamare callback
.
Di solito è più sicuro fornire initialValue
perché ci sono tre output possibili senza initialValue
, come mostrato nell'esempio seguente.
var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x ); var maxCallback2 = ( max, cur ) => Math.max( max, cur ); // reduce() without initialValue [ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42 [ { x: 22 } ].reduce( maxCallback ); // { x: 22 } [ ].reduce( maxCallback ); // TypeError // map/reduce; better solution, also works for empty or larger arrays [ { x: 22 }, { x: 42 } ].map( el => el.x ) .reduce( maxCallback2, -Infinity );
Supponiamo che si sia verificato il seguente uso di reduce()
:
[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) { return accumulator + currentValue; });
Il callback verrebbe invocato quattro volte, con gli argomenti e i valori restituiti in ogni chiamata come segue:
callback |
accumulator |
currentValue |
currentIndex |
array |
valore ritornato |
---|---|---|---|---|---|
prima chiamata | 0 |
1 |
1 | [0, 1, 2, 3, 4] |
1 |
seconda chiamata | 1 |
2 |
2 | [0, 1, 2, 3, 4] |
3 |
terza chiamata | 3 |
3 |
3 | [0, 1, 2, 3, 4] |
6 |
quarta chiamata | 6 |
4 |
4 | [0, 1, 2, 3, 4] |
10 |
Il valore restituito da reduce()
sarà quello dell'ultima chiamata del callback (10
).
È inoltre possibile fornire una {{jsxref("Functions/Arrow_functions", "Arrow Function","",1)}} al posto di una funzione completa. Il seguente codice produrrà lo stesso output del codice nel blocco sopra riportato:
[0, 1, 2, 3, 4].reduce( (accumulator, currentValue, currentIndex, array) => accumulator + currentValue );
Se dovessi fornire initialValue
come secondo argomento a reduce()
, il risultato sarebbe simile a questo:
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { return accumulator + currentValue; }, 10);
callback |
accumulator |
currentValue |
currentIndex |
array |
valore restituito |
---|---|---|---|---|---|
prima chiamata | 10 |
0 |
0 |
[0, 1, 2, 3, 4] |
10 |
seconda chiamata | 10 |
1 |
1 |
[0, 1, 2, 3, 4] |
11 |
terza chiamata | 11 |
2 |
2 |
[0, 1, 2, 3, 4] |
13 |
quarta chiamata | 13 |
3 |
3 |
[0, 1, 2, 3, 4] |
16 |
quinta chiamata | 16 |
4 |
4 |
[0, 1, 2, 3, 4] |
20 |
Il valore restituito da reduce()
in questo caso sarebbe 20
.
var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) { return accumulator + currentValue; }, 0); // sum è 6
In alternativa scritto con una arrow function:
var total = [ 0, 1, 2, 3 ].reduce( ( accumulator, currentValue ) => accumulator + currentValue, 0 );
Per riassumere i valori contenuti in un array di oggetti, devi fornire initialValue
, in modo che ogni elemento passi attraverso la tua funzione
var initialValue = 0; var sum = [{x: 1}, {x: 2}, {x: 3}].reduce(function (accumulator, currentValue) { return accumulator + currentValue.x; },initialValue) console.log(sum) // logs 6
In alternativa scritto con una arrow function:
var initialValue = 0; var sum = [{x: 1}, {x: 2}, {x: 3}].reduce( (accumulator, currentValue) => accumulator + currentValue.x ,initialValue ); console.log(sum) // logs 6
var flattened = [[0, 1], [2, 3], [4, 5]].reduce( function(accumulator, currentValue) { return accumulator.concat(currentValue); }, [] ); // flattened is [0, 1, 2, 3, 4, 5]
In alternativa scritto con una arrow function:
var flattened = [[0, 1], [2, 3], [4, 5]].reduce( ( accumulator, currentValue ) => accumulator.concat(currentValue), [] );
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice']; var countedNames = names.reduce(function (allNames, name) { if (name in allNames) { allNames[name]++; } else { allNames[name] = 1; } return allNames; }, {}); // countedNames is: // { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
var people = [ { name: 'Alice', age: 21 }, { name: 'Max', age: 20 }, { name: 'Jane', age: 20 } ]; function groupBy(objectArray, property) { return objectArray.reduce(function (acc, obj) { var key = obj[property]; if (!acc[key]) { acc[key] = []; } acc[key].push(obj); return acc; }, {}); } var groupedPeople = groupBy(people, 'age'); // groupedPeople is: // { // 20: [ // { name: 'Max', age: 20 }, // { name: 'Jane', age: 20 } // ], // 21: [{ name: 'Alice', age: 21 }] // }
// friends - an array of objects // where object field "books" - list of favorite books var friends = [{ name: 'Anna', books: ['Bible', 'Harry Potter'], age: 21 }, { name: 'Bob', books: ['War and peace', 'Romeo and Juliet'], age: 26 }, { name: 'Alice', books: ['The Lord of the Rings', 'The Shining'], age: 18 }]; // allbooks - list which will contain all friends' books + // additional list contained in initialValue var allbooks = friends.reduce(function(accumulator, currentValue) { return [...accumulator, ...currentValue.books]; }, ['Alphabet']); // allbooks = [ // 'Alphabet', 'Bible', 'Harry Potter', 'War and peace', // 'Romeo and Juliet', 'The Lord of the Rings', // 'The Shining' // ]
Note: Se si utilizza un ambiente compatibile con {{jsxref("Set")}} e {{jsxref("Array.from()")}}, è possibile utilizzare let orderedArray = Array.from(new Set(myArray));
per ottenere un array in cui sono stati rimossi gli elementi duplicati.
var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd']; var myOrderedArray = myArray.reduce(function (accumulator, currentValue) { if (accumulator.indexOf(currentValue) === -1) { accumulator.push(currentValue); } return accumulator }, []) console.log(myOrderedArray);
/** * Esegue promises da un array di funzioni che possono restituire promises * in modo concatenato * * @param {array} arr - promise arr * @return {Object} promise object */ function runPromiseInSequence(arr, input) { return arr.reduce( (promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(input) ); } // promise function 1 function p1(a) { return new Promise((resolve, reject) => { resolve(a * 5); }); } // promise function 2 function p2(a) { return new Promise((resolve, reject) => { resolve(a * 2); }); } // function 3 - sarà avvolta in una promise risolta da .then() function f3(a) { return a * 3; } // promise function 4 function p4(a) { return new Promise((resolve, reject) => { resolve(a * 4); }); } const promiseArr = [p1, p2, f3, p4]; runPromiseInSequence(promiseArr, 10) .then(console.log); // 1200
// Elementi da utilizzare per la composizione const double = x => x + x; const triple = x => 3 * x; const quadruple = x => 4 * x; // Function composition enabling pipe functionality const pipe = (...functions) => input => functions.reduce( (acc, fn) => fn(acc), input ); // Funzioni composte per la moltiplicazione di valori specifici const multiply6 = pipe(double, triple); const multiply9 = pipe(triple, triple); const multiply16 = pipe(quadruple, quadruple); const multiply24 = pipe(double, triple, quadruple); // Utilizzo multiply6(6); // 36 multiply9(9); // 81 multiply16(16); // 256 multiply24(10); // 240
if (!Array.prototype.mapUsingReduce) { Array.prototype.mapUsingReduce = function(callback, thisArg) { return this.reduce(function(mappedArray, currentValue, index, array) { mappedArray[index] = callback.call(thisArg, currentValue, index, array); return mappedArray; }, []); }; } [1, 2, , 3].mapUsingReduce( (currentValue, index, array) => currentValue + index + array.length ); // [5, 7, , 10]
// Production steps of ECMA-262, Edition 5, 15.4.4.21 // Reference: http://es5.github.io/#x15.4.4.21 // https://tc39.github.io/ecma262/#sec-array.prototype.reduce if (!Array.prototype.reduce) { Object.defineProperty(Array.prototype, 'reduce', { value: function(callback /*, initialValue*/) { if (this === null) { throw new TypeError( 'Array.prototype.reduce ' + 'called on null or undefined' ); } if (typeof callback !== 'function') { throw new TypeError( callback + ' is not a function'); } // 1. Let O be ? ToObject(this value). var o = Object(this); // 2. Let len be ? ToLength(? Get(O, "length")). var len = o.length >>> 0; // Steps 3, 4, 5, 6, 7 var k = 0; var value; if (arguments.length >= 2) { value = arguments[1]; } else { while (k < len && !(k in o)) { k++; } // 3. If len is 0 and initialValue is not present, // throw a TypeError exception. if (k >= len) { throw new TypeError( 'Reduce of empty array ' + 'with no initial value' ); } value = o[k++]; } // 8. Repeat, while k < len while (k < len) { // a. Let Pk be ! ToString(k). // b. Let kPresent be ? HasProperty(O, Pk). // c. If kPresent is true, then // i. Let kValue be ? Get(O, Pk). // ii. Let accumulator be ? Call( // callbackfn, undefined, // « accumulator, kValue, k, O »). if (k in o) { value = callback(value, o[k], k, o); } // d. Increase k by 1. k++; } // 9. Return accumulator. return value; } }); }
Se hai bisogno di supportare motori JavaScript veramente obsoleti che non supportano Object.defineProperty()
, è meglio non applicare polyfills ai metodi di Array.prototype
, poiché non puoi renderli non enumerabili.
Specifica | Stato | Commento |
---|---|---|
{{SpecName('ES5.1', '#sec-15.4.4.21', 'Array.prototype.reduce()')}} | {{Spec2('ES5.1')}} | Definizione iniziale Implementato in JavaScript 1.8. |
{{SpecName('ES6', '#sec-array.prototype.reduce', 'Array.prototype.reduce()')}} | {{Spec2('ES6')}} | |
{{SpecName('ESDraft', '#sec-array.prototype.reduce', 'Array.prototype.reduce()')}} | {{Spec2('ESDraft')}} |
La tabella di compatibilità in questa pagina è generata a partire da dati strutturati. Se desideri contribuire ai dati, visita https://github.com/mdn/browser-compat-data e inviaci una pull request.
{{Compat("javascript.builtins.Array.reduce")}}