文档里说reduce()方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始合并,最终为一个值。

reduce()

reduce() 函数接收2个参数(M: 必填, O: 可选):

  • (M) 回调reducer 函数 处理先前的结算结果和下一个元素直到序列结束。
  • (O) 初值 作为第一次调用回调时的第一个参数。

所以,让我们先看一个普通用法,之后再看一个复杂用法。

普通用法 (累加,关联)

我们正在逛亚马逊(单价为美元$) 我们的购物车实在太满了,我们来计算一下总价吧:

// 当前的购物清单
var items = [{price: 10}, {price: 120}, {price: 1000}];

// reducer函数
var reducer = function add(sumSoFar, nextPrice) { return sumSoFar + nextPrice.price; };

// 开始运行
var total = items.reduce(reducer, 0);

console.log(total); // 1130

reduce函数可选的参数在第一个例子里是基本变量数字0,但是它也可以是一个对象,数组… 而不仅是基本类型,之后我们将会看到。

现在,我们收到一个20$的优惠券。

var total = items.reduce(reducer,-20);

console.log(total); // 1110

进阶用法(结合)

第二种用法的例子是ReduxcombineReducers函数源码里用到的。

此创意是将reducer函数拆分为独立的函数,最后组合成一个新的单一的大reducer函数

为了说明,我们创建一个单一的对象,包含一些可以计算不同货币($, €…)的总价值的reducer函数。

var reducers = {
  totalInDollar: function(state, item) {
    state.dollars += item.price;
    return state;
  },
  totalInEuros : function(state, item) {
    state.euros += item.price * 0.897424392;
    return state;
  },
  totalInPounds : function(state, item) {
    state.pounds += item.price * 0.692688671;
    return state;
  },
  totalInYen : function(state, item) {
    state.yens += item.price * 113.852;
    return state;
  }
  // more...
};

然后我们建立一个瑞士军刀函数

  • 能够调用每一部分的reduce函数
  • 返回一个新的reducer回调函数
var combineTotalPriceReducers = function(reducers) {
  return function(state, item) {
    return Object.keys(reducers).reduce(
      function(nextState, key) {
        reducers[key](state, item);
        return state;
      },
      {}      
    );
  }
};

现在,我们来看一下如何使用它。

var bigTotalPriceReducer = combineTotalPriceReducers(reducers);

var initialState = {dollars: 0, euros:0, yens: 0, pounds: 0};

var totals = items.reduce(bigTotalPriceReducer, initialState);

console.log(totals);

/*
Object {dollars: 1130, euros: 1015.11531904, yens: 127524.24, pounds: 785.81131152}
*/

我希望这种方法可以使你在自己的需求内使用reduce()函数时有新的想法。

使用reduce函数也可以实现保存每一次计算结果的功能。这在Ramdajs里的scan函数已经实现了。

在JSFiddle里运行