Array.prototype.reduce()
Baseline
Widely available
This feature is well established and works across many devices and browser versions. Itâs been available across browsers since â¨2015å¹´7æâ©.
reduce() æ¹æ³å°ä¸åç´¯å å¨åé£å䏿¯é
å
ç´ ï¼ç±å·¦è³å³ï¼å³å
¥åå¼å½å¼ï¼å°é£ååçºå®ä¸å¼ã
å試ä¸ä¸
const array1 = [1, 2, 3, 4];
// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue,
);
console.log(sumWithInitial);
// Expected output: 10
èªæ³
arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)
忏
callback-
: ç¨æ¼èçé£å䏿¯åå ç´ çå½å¼ï¼å¯å³å ¥åå忏ï¼
accumulator-
ç¨ä¾ç´¯ç©åå¼å½å¼åå³å¼çç´¯å å¨ï¼accumulatorï¼æ
initialValueï¼è¥ææä¾ç話ï¼è©³å¦ä¸æï¼ãç´¯å 卿¯ä¸ä¸æ¬¡å¼å«å¾ï¼æåå³çç´¯å æ¸å¼ã currentValue-
åé£åç®åæè¿ä»£èçä¸çå ç´ ã
currentIndex鏿æ§-
åé£åç®åæè¿ä»£èçä¸çå ç´ ä¹ç´¢å¼ãè¥æå³å ¥
initialValueï¼åç±ç´¢å¼ 0 ä¹å ç´ éå§ï¼è¥ç¡åèªç´¢å¼ 1 ä¹å ç´ éå§ã array鏿æ§-
å¼å«
reduce()æ¹æ³çé£åã
-
initialValue鏿æ§- : æ¼ç¬¬ä¸æ¬¡å¼å«
callbackæè¦å³å ¥çç´¯å å¨åå§å¼ãè¥æ²ææä¾åå§å¼ï¼ååé£åç第ä¸åå ç´ å°æè¢«ç¶ä½åå§çç´¯å å¨ãå妿¼ä¸å空é£åå¼å«reduce()æ¹æ³ä¸æ²ææä¾ç´¯å å¨åå§å¼ï¼å°æç¼çé¯èª¤ã
- : æ¼ç¬¬ä¸æ¬¡å¼å«
-
åå³å¼
ç°¡åå¾ççµæå¼ã
æè¿°
reduce() æå°æ¯ä¸åç®åè¿ä»£å°çé£åå
ç´ ï¼é¤äºç©ºå¼ä»¥å¤ï¼å·è¡ callback å½å¼ï¼åå¼å½å¼ææ¥æ¶åå忏ï¼
accumulatorcurrentValuecurrentIndexarray
ç¶åå¼å½å¼ç¬¬ä¸æ¬¡è¢«å¼å«æï¼accumulator è currentValue çå¼å¯è½çºå
©ç¨®ä¸åççæ³ï¼è¥å¨å¼å« reduce() æææä¾ initialValueï¼å accumulator å°æçæ¼ initialValueï¼ä¸ currentValue æçæ¼é£åä¸ç第ä¸åå
ç´ å¼ï¼è¥æ²ææä¾ initialValueï¼å accumulator æçæ¼é£åç第ä¸åå
ç´ å¼ï¼ä¸ currentValue å°æçæ¼é£åç第äºåå
ç´ å¼ã
å註ï¼åå¦ initialValue æªè¢«æä¾ï¼reduce() å°æè·³é第ä¸åé£åç´¢å¼ï¼å¾é£åç´¢å¼ 1 éå§å·è¡åå¼å½å¼ãè¥ææä¾ initialValueï¼åæç±é£åç´¢å¼ 0 éå§å·è¡ã
è¥é£åçºç©ºä¸æ²ææä¾ initialValueï¼å°ææåº TypeErrorãåå¦é£ååªæä¸åå
ç´ ï¼ç¡è«å
¶ç´¢å¼ä½ç½®çºä½ï¼ä¸¦ä¸æ²ææä¾ initialValueï¼æå¦ææä¾äº initialValue ä½é£åçºç©ºï¼åæ¤å¯ä¸çå¼å°æè¢«ç´æ¥åå³è䏿å¼å« callback å½å¼ã
æä¾ç´¯å å¨åå§å¼é常è¼çºå®å
¨ï¼å çºå¨æ²æå³å
¥ initialValue çæ
æ³ä¸ææä¸ç¨®å¯è½ç輸åºçµæï¼å¦ä¸åç¯ä¾ï¼
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);
reduce() å¦ä½éä½
åè¨ reduce() 以ä¸ä¾æ¹å¼ä½¿ç¨ï¼
[0, 1, 2, 3, 4].reduce(
function (accumulator, currentValue, currentIndex, array) {
return accumulator + currentValue;
},
);
æå³å ¥çåå¼å½å¼å°è¢«å¼å«åæ¬¡ï¼æå³å ¥ç忏èåå³å¼å¦ä¸æç¤ºï¼
callback |
accumulator |
currentValue |
currentIndex |
array |
return value |
|---|---|---|---|---|---|
| first call | 0 |
1 |
1 |
[0, 1, 2, 3, 4] |
1 |
| second call | 1 |
2 |
2 |
[0, 1, 2, 3, 4] |
3 |
| third call | 3 |
3 |
3 |
[0, 1, 2, 3, 4] |
6 |
| fourth call | 6 |
4 |
4 |
[0, 1, 2, 3, 4] |
10 |
reduce() çæçµåå³å¼å°ææ¯æå¾ä¸æ¬¡å¼å«åå¼å½å¼çåå³å¼ (10)ã
ä½ ä¹å¯ä»¥å³å ¥ä¸åç®é å½å¼ä¾æ¿ä»£ä¸å宿´çå½å¼ã䏿¹çç¨å¼ç¢¼å·è¡ççµæå°èåè¿°ä¾åç¸åã
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr);
å¦æä½ ææä¾ç¬¬äºå忏å¼çµ¦ reduce()ï¼å·è¡ççµæå¦ä¸ï¼
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
}, 10);
callback |
accumulator |
currentValue |
currentIndex |
array |
return value |
|---|---|---|---|---|---|
| first call | 10 |
0 |
0 |
[0, 1, 2, 3, 4] |
10 |
| second call | 10 |
1 |
1 |
[0, 1, 2, 3, 4] |
11 |
| third call | 11 |
2 |
2 |
[0, 1, 2, 3, 4] |
13 |
| fourth call | 13 |
3 |
3 |
[0, 1, 2, 3, 4] |
16 |
| fifth call | 16 |
4 |
4 |
[0, 1, 2, 3, 4] |
20 |
reduce() å·è¡ççµæå°ææ¯ 20ã
ç¯ä¾
>å 總ææé£ä¾ä¹å ç´ å¼
var sum = [0, 1, 2, 3].reduce(function (a, b) {
return a + b;
}, 0);
// sum is 6
å¦å¤ï¼ä¹å¯ä»¥å¯«æç®é å½å¼ï¼
var total = [0, 1, 2, 3].reduce((acc, cur) => acc + cur, 0);
æ¤å¹³ä¸åå¤ç¶é£å
var flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce(function (a, b) {
return a.concat(b);
}, []);
// flattened is [0, 1, 2, 3, 4, 5]
å¦å¤ï¼ä¹å¯ä»¥å¯«æç®é å½å¼ï¼
var flattened = [
[0, 1],
[2, 3],
[4, 5],
].reduce((acc, cur) => acc.concat(cur), []);
è¨ç®ç¸åå ç´ æ¸é並以ç©ä»¶éµå¼é¡¯ç¤º
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 }
ä½¿ç¨ spread éç®åè給å®åå§å¼ï¼çµåç©ä»¶ä¸çé£åå ç´
// 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 (prev, curr) {
return [...prev, ...curr.books];
},
["Alphabet"],
);
// allbooks = [
// 'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
// 'Romeo and Juliet', 'The Lord of the Rings',
// 'The Shining'
// ]
ç§»é¤é£åä¸çéè¤é ç®
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
let result = arr.sort().reduce((init, current) => {
if (init.length === 0 || init[init.length - 1] !== current) {
init.push(current);
}
return init;
}, []);
console.log(result); //[1,2,3,4,5]
åºåå·è¡ Promise
/**
* Runs promises from promise array in chained manner
*
* @param {array} arr - promise arr
* @return {Object} promise object
*/
function runPromiseInSequense(arr) {
return arr.reduce((promiseChain, currentPromise) => {
return promiseChain.then((chainedResult) => {
return currentPromise(chainedResult).then((res) => res);
});
}, Promise.resolve());
}
// promise function 1
function p1() {
return new Promise((resolve, reject) => {
resolve(5);
});
}
// promise function 2
function p2(a) {
return new Promise((resolve, reject) => {
resolve(a * 2);
});
}
// promise function 3
function p3(a) {
return new Promise((resolve, reject) => {
resolve(a * 3);
});
}
const promiseArr = [p1, p2, p3];
runPromiseInSequense(promiseArr).then((res) => {
console.log(res); // 30
});
Polyfill
// 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;
},
});
}
妿ééè¦æ¯æ´èèå°ä¸æ¯æ´ Object.defineProperty ç JavaScript å¼æï¼æå¥½ä¸è¦ polyfill Array.prototype æ¹æ³ï¼å çºä½ ç¡æ³ä»¤å
¶ä¸å¯æèï¼non-enumerableï¼ã
è¦ç¯
| Specification |
|---|
| ECMAScript® 2026 Language Specification > # sec-array.prototype.reduce > |