JS reduce()

142 阅读3分钟

reduce()

干嘛的?

reduce()方法对数组中的每个元素执行一个自己提供的 reducer 函数(升序执行),将其结果汇总为单个返回值。

demo

const arr = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1+2+3+4
console.log(arr.reduce(reducer));
// expected output: 10

// 5+1+2+3+4
console.log(arr.reduce(reducer))
// expected output: 15

语法

arr.reduce(callback(accumulator, currentValue[, index[, array]])[,initialValue])

callback

callback 执行数组中每个值(如果没有提供 initialValue 则第一个值除外)的函数,包含四个参数

callback 的参数name是否可选
accumulator累计器累计回调的返回值;上一次调用时返回的累计值,或 initialValuefalse
currentValue数组中正在处理的元素false
index数组中正在处理的当前元素的索引。如果提供了 initialValue,则起始索引号为 0,否则从索引 1 起始true
array调用 reduce()的数组true

initialValue

作为第一次调用 callback 函数时的第一个参数的值。如果没有提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用 reduce 将报错

返回值

函数累计处理的结果

注意

如果没有提供 initialValue,reduce 会从索引 1 的地方开始执行 callback,跳过第一个索引。如果提供 initialValue,从索引 0 开始

如果数组为空且没有提供 initialValue,会抛出 TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供 initialValue, 或者有提供 initialValue 但是数组为空,那么此唯一值将被返回并且 callback 不会被执行。

name有 initialValue无 initialValue
空数组initialValue 作为唯一值,callback 不执行抛出 TypeError
数组仅有一个元素据情况数组中的元素作为唯一值,callback 不执行

demo2

var maxCallback = (acc, cur) => Math.max( acc.x, cur.x);
// reduce() 没有初始值
[{x: 2},{x: 22},{x:42}].reduce(maxCallback)

/**
    第一次
    acc {x:2}
    cur {x:22}
    Math.max(2,22) = 22
    第二次
    acc 22
    cur {x:42}
    所以 acc.x : undefined
    Math.max(undefined,数值) : undefined
**/
[{x: 2},{x: 22}].reduce(maxCallback) // 22
/**
    第一次
    acc {x:2}
    cur {x:22}
    Math.max(2,22) = 22
**/
[{x:2}].reduce(maxCallback); // {x:2}

// 数组仅有一个元素+无initialValue,那么此唯一值将被返回并且 callback 不会被执行
[].reduce(maxCallback); // TypeError
// 空数组+无initialValue,抛出TypeError
var maxCallback2 = (max, cur) => Math.max(max, cur)
// map/reduce; 这是更好的方案,即使传入空数组或更大数组也可正常执行
[ { x: 22 }, { x: 42 } ].map( el => el.x )
                        .reduce( maxCallback2, -Infinity );
// -Infinity无穷小,任何数都比它大,写在这,也保证了有initialValue

可用场景

  • 数组里所有值的和
  • 累加对象数组里的值
  • 计算数组中每个元素出现的次数
  • 数组去重
  • .....

计算数组中每个元素出现的次数

var names = ['Alice','Bob','Tiff','Bruce','Alice'];

var countedNames = names.reduce(function(allNames, name){
    console.log("allNames,name", allNames, name);
    /**
    allNames,name {} Alice
    allNames,name {Alice: 1} Bob
    allNames,name {Alice: 1, Bob: 1} Tiff
    allNames,name {Alice: 1, Bob: 1, Tiff: 1} Bruce
    allNames,name {Alice: 1, Bob: 1, Tiff: 1, Bruce: 1} Alice
    **/
    if(name in allNames){
        allNames[name]++;
    }
    else {
        allNames[name] = 1;
    }
    return allNames;
},{})
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

更多查看

MDN-REDUCE()