Array.prototype.reduce()
reduce() 方法对数组中的每个元素执行一个reducer函数(升序执行),将其结果汇总为单个返回值。
const arr1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(arr1.reduce(reducer));
// output: 10
// 5 + 1 + 2 + 3 + 4
console.log(arr1.reduce(reducer, 5));
// output: 15
一、语法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
1.参数
callback
执行数组中每个值(如果没有提供 initialValue,则第一个值除外)的函数,包含四个参数:
accumulator
累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
currentValue
数组中正在处理的元素。
index:可选
数组中正在处理的当前元素的索引。 如果提供了 initialValue,则起始索引号为0,否则从索引1起始。
array:可选
调用reduce()的数组。
initialValue:可选
作为第一次调用 callback 函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
2.返回值
函数累计处理的结果。
二、描述
回调函数第一次执行时,accumulator 和 currentValue 的取值有两种情况:
如果调用reduce()时提供了initialValue,accumulator取值为initialValue,currentValue取数组中的第一个值;
如果没有提供 initialValue,那么accumulator取数组中的第一个值,currentValue取数组中的第二个值。
注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
三、举例
1.求出数组里所有值的和
let sum = [ 0, 1, 2, 3 ].reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 6
2.累加对象数组里的值
let total = [{x: 1}, {x:2}, {x:3}].reduce((acc, cur) => acc + cur.x, 0);
console.log(total); // 6
3.将二维数组转化为一维
let flattened = [[0, 1], [2, 3], [4, 5]].reduce((acc, cur) => acc.concat(cur), []);
console.log(flattened); // [0, 1, 2, 3, 4, 5]
4.计算数组中每个元素出现的次数
let names = ['lxcan', 'splendid', 'ican', 'volcano', 'lxcan'];
let countedNames = names.reduce((allNames, name) => {
if (name in allNames) {
allNames[name]++;
} else {
allNames[name] = 1;
}
return allNames;
}, {});
console.log(countedNames);
// { 'lxcan': 2, 'splendid': 1, 'ican': 1, 'volcano': 1 }
5.按属性对object分类
let peoples = [
{ name: 'lxcan', age: 20 },
{ name: 'ican', age: 20 },
{ name: 'splendid', age: 18 }
];
function groupBy(arr, property) {
return arr.reduce((acc, obj) => {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
let groupedPeople = groupBy(peoples, 'age');
console.log(groupedPeople);
// {
// 18: [{ name: 'splendid', age: 18 }]
// 20: [
// { name: 'lxcan', age: 20 },
// { name: 'ican', age: 20 }
// ],
// }
6.使用扩展运算符和initialValue绑定包含在对象数组中的数组
// friends - 对象数组
let friends = [{
name: 'Anna',
books: ['Bible', 'Harry Potter'],
age: 21
}, {
name: 'Bob',
books: ['War and peace', 'Romeo and Juliet'],
age: 26
}, {
name: 'Alice',
books: ['The Shining'],
age: 18
}];
// allbooks - 包含所有朋友的书 + initialValue 中的附加列表
let allBooks = friends.reduce(function(prev, curr) {
return [...prev, ...curr.books];
}, ['Alphabet']);
console.log(allBooks);
// ['Alphabet', 'Bible', 'Harry Potter', 'War and peace', 'Romeo and Juliet', 'The Shining']
7.功能型函数封装
const double = x => 2 * x;
const triple = x => 3 * x;
const quadruple = x => 4 * x;
// 对功能函数进行封装
const pipe = (...functions) => {
return input => functions.reduce((acc, fn) => fn(acc), input)
};
// 用于特定值组合乘法的复合函数
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);
// 使用
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240
8.使用 reduce 实现map
if (!Array.prototype.mapByReduce) {
Array.prototype.mapByReduce = function(callback, thisArg) {
return this.reduce(function(mappedArray, currentValue, index, array) {
mappedArray[index] = callback.call(thisArg, currentValue, index, array);
return mappedArray;
}, []);
};
}
let arr = [1, 2, 3].mapByReduce((value, index, array) => value + index + array.length);
console.log(arr); // [4, 6, 8]