2

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]

lxcan
337 声望32 粉丝