Array.prototype.reduce()
方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。对空数组时不会执行回调函数。
语法:
arr.reduce(callbackfn [, initialValue]);
类型声明
interface Array<T> {reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T;reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T,initialValue: T): T;reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U,initialValue: U): U;}
参数说明:
参数 | 说明 | 类型 |
---|---|---|
callbackfn | 回调函数,用于遍历数组成员时执行 | function |
initialValue | (可选)累加器初始值,用作第一个调用回调函数的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用将报错。 | any |
callbackfn
函数的参数:
previousValue
:累加器累加回调的返回值,它是上一次调用回调时返回的累积值,或 initialValue
currentValue
:当前数组中处理的元素index
:数组中正处理的当前元素的索引array
:被调用的数组返回值:
返回函数累计处理的结果。
reduce()
方法为数组中的每一个元素依次执行 callback
回调函数,不包括数组中被删除或从未被赋值的元素。
回调函数第一次执行时,acc
和 currentValue
的取值有两种情况:
initialValue
,累加器 acc
取值为 initialValue
,currentValue
取数组中的第一个值initialValue
,累加器 acc
取数组中的第一个值作为初始值,currentValue
取数组中的第二个值。initialValue
,从索引 0 开始执行回调函数。initialValue
,reduce
会从索引 1 的地方开始执行回调函数,跳过第一个索引。initialValue
,会抛出 TypeError
。initialValue
, 或者有提供 initialValue
但是数组为空,那么此唯一值将被返回并且 callback
不会被执行。假如运行下段代码:
[0, 1, 2, 3, 4].reduce((acc, val, index, arr) => acc + val);
回调函数被调用四次,每次调用的参数和返回值如下表所示。
callback 回调函数 | acc 累加器 | val 当前值 | index 当前索引 | arr | 返回值 |
---|---|---|---|---|---|
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。
如果你打算提供一个初始值作为 reduce
方法的第二个参数,以下是运行过程及结果。
[0, 1, 2, 3, 4].reduce((acc, val, index, arr) => accumulator + currentValue, 10);
callback 回调函数 | acc 累加器 | val 当前值 | index 当前索引 | arr | 返回值 |
---|---|---|---|---|---|
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。
数组成员为数字类型时。
const res = [1, 2, 3, 4, 5].reduce((acc, item) => acc + item, 0);console.log(res);// 15
数组成员为对象类型时。
const arr = [{ total: 1 }, { total: 2 }, { total: 3 }, { total: 4 }, { total: 5 }];const res = arr.reduce((acc, { total }) => acc + total, 0);console.log(res);// 15
将数组的每项转换为固定格式的字符串,每项直接以分号作为分隔。
const arr = [{ key: 'foo', value: 1 },{ key: 'bar', value: 2 },{ key: 'baz', value: 3 },];const res = arr.reduce((acc, { key, value }) => acc + `${key}=${value}&`, '?');console.log(res);// "?foo=1&bar=2&baz=3&"
只要目标是将数组聚合为唯一的元素时,都可以考虑使用 reduce
const arr = [{ id: 1, type: 'a', name: 'foo' },{ id: 2, type: 'b', name: 'bar' },{ id: 3, type: 'c', name: 'baz' },];const res = arr.reduce((acc, { id, type, name }) => {acc[id] = { type, name };return acc;}, {});console.log(res);// { 1: { name: 'foo', type: 'a'}, 2: { name: 'bar', type: 'b'}, { name: 'baz', type: 'c' }}
提供初始值通常更安全。
没有提供初始值。
const maxCallback = ( pre, current ) => Math.max( pre.x, current.x )[{ x: 22}, { x: 42}].reduce(maxCallback)// 42[{ x: 22}].reduce(maxCallback)// { x: 22 }[].reduce(maxCallback)// TypeError
提供初始值。
const maxCallback = ( max, current ) => Math,max( max, current )[{ x: 22 }, { x: 42 }].map( el => el.x ).reduce( maxCallback2, -Infinity );
// 数组求和const sum = [0, 1, 2, 3].reduce((acc, cur) => acc + cur, 0);// 6// 数组求积const product = [1, 2, 3, 4, 5].reduce((a, b) => a * b, 1);// 120// 数组最大值const max = [1, 2, 3, 4, 5].reduce((a, b) => (a > b ? a : b));// 5
找出长度最长的数组元素。
const findLongest = (entries) =>entries.reduce((prev, cur) => (cur.length > prev.length ? cur : prev), '');console.log(findLongest([1, 2, 3, 'ab', 4, 'bcd', 5, 6785, 4]));// 'bcd'
const arr = [[0, 1],[2, 3],[4, 5],];const res = arr.reduce((a, b) => a.concat(b), []);console.log(res);// [0, 1, 2, 3, 4, 5]
你也可以写成箭头函数的形式:
var flattened = [[0, 1],[2, 3],[4, 5],].reduce((acc, cur) => acc.concat(cur), []);
const names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];const countedNames = names.reduce((allNames, name) => {if (name in allNames) {allNames[name]++;} else {allNames[name] = 1;}return allNames;}, {});// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
const arr = [0.3, 1.2, 3.4, 0.2, 3.2, 5.5, 0.4];function reduceMaxMin(acc, value) {reuturn {min: Math.min(acc.min, value),max: Math.max(acc.max, value)}}const initMinMax = {min: Number.MIN_VALUE,max: Number.MAX_VALUE}const minMax = arr.reduce(reduceMaxMin, initMinMax);console.log(minMax);// { min: 0.2, max: 5.5}
if (!Array.prototype.reduce) {Object.defineProperty(Array.prototype, 'reduce', {value: function (callback) {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');}// 将数组对象化const obj = Object(this);const len = obj.length >>> 0;let index = 0;let accumulator;// 处理累加器(也就是 reduce 方法第二个参数)if (arguments.length >= 2) {// 累加器accumulator = arguments[1];} else {while (index < len && !(index in obj)) {index++;}if (index >= len) {throw new TypeError('Reduce of empty array with no initial value');}accumulator = obj[index++];}// 走有累加器的那种实现while (index < len) {if (index in obj) {accumulator = callback(accumulator, obj[index], index, obj);}index++;}return accumulator;},});}