用生命谱写代码的赞歌

0%

JS数组 reduce 方法详解

reduce 语法

1
arr.reduce(callback[, initialValue])
  1. callback 表示执行数组中每个值的函数,包含四个参数:
    • previous 上次调用回调返回的值,或者是提供的初始值(initialValue)
    • currentValue 数组中当前被处理的元素
    • index 当前元素在数组中的索引
    • array 调用 reduce 的数组
    • initialValue 作为第一次调用 callback 的第一个参数

简单应用

1
2
3
4
5
6
var items = [25, 175, 2500];
var reducer = function add(sumSoFar, item) {
return sumSoFar + item;
};
var total = items.reduce(reducer, 0);
console.log(total); // 2700

reduce 函数初始值为0,不断累加,完成数据求和。同理,初始值也可以是对象类型。

1
2
3
4
5
6
7
var items = [25, 175, 2500];
var reducer = function add(sumSoFar, item) {
sumSoFar.sum = sumSoFar.sum + item;
return sumSoFar;
};
var total = items.reduce(reducer, {sum: 0});
console.log(total); // {sum: 2700}

进阶应用

下面就是 manager 函数的实现,它需要 reducers 对象作为参数,并返回一个 callback 类型的函数,作为 reduce 的第一个参数。在该函数内部,则执行多维的叠加工作(Object.keys())。

通过这种分治的思想,可以完成目标对象多个属性的同时叠加,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var reducers = {
totalInEuros : function(state, item) {
return state.euros += item.price * 1.5;
},
totalInYen : function(state, item) {
return state.yens += item.price * 0.8;
}
};
var manageReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
}, {});
}
};
var bigTotalPriceReducer = manageReducers(reducers);
var initialState = {euros:0, yens: 0};
var items = [{price: 10}, {price: 120}, {price: 1000}];
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals); // {euros: 1695, yens: 904}

举个例子

某同学考试成绩如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var result = [
{
subject: 'math',
score: 99
},
{
subject: 'chinese',
score: 84
},
{
subject: 'english',
score: 82
}
];

利用 reduce 求总成绩

1
2
3
4
5
6
7
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, 0); // 265
// 如果该同学因为违纪总成绩被扣10分
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, -10); // 255

下面增加点难度,假如该同学总成绩中各科比重所占不同,分别为50%,30%,20%,如何求出最终权重结果?

1
2
3
4
5
6
7
8
9
10
11
var weight = {
math: 0.5,
chinese: 0.3,
english: 0.2
};
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, -10); // 255
var qsum = result.reduce(function(prev, cur) {
return cur.score * weight[cur.subject] + prev;
}, 0) // 91.10000000000001

利用 reduce 求一串字符串每个字母出现次数

1
2
3
4
5
var arrString = 'abcdaabc';
arrString.split('').reduce(function(res, cur) {
res[cur] ? res[cur] ++ : res[cur] = 1
return res;
}, {}); // {a: 3, b: 2, c: 2, d: 1}

其他用法,各种各样的类型转换,比如将数组按照一定规则转换为对象:

  1. 一种形式数组转换为另一种形式数组:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [4, 6].reduce(function(res, cur) {
    res.push(cur + 1);
    return res;
    }, []); // [5, 7]

    [4, 6].reduce(function(res, cur) {
    res.a = res.a + cur;
    res.b = res.b + cur;
    return res;
    }, {a: 0, b: 0}); // {a: 10, b: 10}
  2. koa源码中有个 only 模块,整个模块就一个简单的返回 reduce 方法操作的对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var only = function(obj, keys){
    obj = obj || {};
    if ('string' == typeof keys) keys = keys.split(/ +/);
    return keys.reduce(function(ret, key){
    if (null == obj[key]) return ret;
    ret[key] = obj[key];
    return ret;
    }, {});
    };

    通过对 reduce 概念的理解,这个模块主要是想新建并返回一个 obj 对象中存在的 keys 的 object 对象。

    1
    2
    3
    4
    5
    6
    var a = {
      env : 'production',
      proxy : true,
      subdomainOffset : 5
    }
    only(a,['env','proxy'])  // {env:'production',proxy : true}