JS 数组中 reduce 方法详解

2021-06-10 00:09:06 浏览数 (1)

一、reduce 方法

reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值。 也就是说,这个累加器会从第一个累加值开始,不断对累加值和数组中的后续元素调用该累加器,直到数组中的最后一个元素,最后返回得到的累加值。

1、语法

代码语言:javascript复制
array.reduce(callback, initialValue)

2、参数说明

reduce 参数

reduce 参数说明

callback(total, currentValue, index, arr)

必需。用于执行每个数组元素的累加器函数。函数参数: 累加器参数 累加器参数说明 total 必需。初始值, 或者计算结束后的返回值。 currentValue 必需。当前元素 currentIndex 可选。当前元素的索引 arr 可选。当前元素所属的数组对象。

累加器参数

累加器参数说明

total

必需。初始值, 或者计算结束后的返回值。

currentValue

必需。当前元素

currentIndex

可选。当前元素的索引

arr

可选。当前元素所属的数组对象。

累加器参数

累加器参数说明

total

必需。初始值, 或者计算结束后的返回值。

currentValue

必需。当前元素

currentIndex

可选。当前元素的索引

arr

可选。当前元素所属的数组对象。

initialValue

可选。传递给函数的初始值

3、应用

① 简单示例
代码语言:javascript复制
var items = [10, 100, 1000];

// 累加器函数
var reducer = function add(sumSoFar, item) { return sumSoFar   item; };

var total = items.reduce(reducer, 1);

console.log(total); // 1111

可以看出,reduce 函数根据初始值 1,不断的进行叠加,完成最简单的总和的实现

② 返回对象

reduce 函数的返回结果类型和传入的初始值相同,上个实例中初始值为 number 类型,同理,初始值也可为 object 类型

代码语言:javascript复制
var items = [10, 100, 1000];

// 累加器函数
var reducer = function add(sumSoFar, item) {
  sumSoFar.sum = sumSoFar.sum   item;
  return sumSoFar;
};

var total = items.reduce(reducer, { sum: 1 });

console.log(total); // {sum: 1111}
③ 多维度的数据叠加

使用 reduce 方法可以完成多维度的数据叠加 如上例中的初始值 {sum: 0},这仅仅是一个维度的操作,如果涉及到了多个属性的叠加,如 {sum: 0,totalInEuros: 0,totalInYen: 0},则需要相应的逻辑进行处理

在下面的方法中,采用分而治之的方法,即将 reduce 函数第一个参数 callback 封装为一个数组,由数组中的每一个函数单独进行叠加并完成 reduce 操作。所有的一切通过一个 manager 函数来管理流程和传递初始参数。

代码语言:javascript复制
var manageReducers = function (reducers) {
  return function (state, item) {
    return Object.keys(reducers).reduce(
      function (nextState, key) {
        reducers[key](state, item);
        return state;
      },
      {}
    );
  }
};

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

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

代码语言:javascript复制
var reducers = {
  totalInEuros: function (state, item) {
    return state.x  = item.num * 1;
  },
  totalInYen: function (state, item) {
    return state.y  = item.num * 2;
  }
};

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 = {
  x: 1,
  y: 1
};
var items = [
  {
    num: 10
  },
  {
    num: 100
  },
  {
    num: 1000
  }
];
var totals = items.reduce(bigTotalPriceReducer, initialState);

console.log(totals);  // {x: 1111, y: 2221}
③ 场景应用

某同学的期末成绩如下表示

代码语言:javascript复制
var result = [
  {
    subject: 'chinese',
    score: 85
  },
  {
    subject: 'math',
    score: 95
  },
  {
    subject: 'english',
    score: 90
  }
];

如何求该同学的总成绩?

代码语言:javascript复制
var sum = result.reduce(function (prev, cur) {
  return cur.score   prev;
}, 0);

假设该同学因为违纪被处罚在总成绩总扣 10 分,只需要将初始值设置为 -10 即可:

代码语言:javascript复制
var sum = result.reduce(function (prev, cur) {
  return cur.score   prev;
}, -10);

我们来给这个例子增加一点难度 假如该同学的总成绩中,各科所占的比重不同,分别为 50%,30%,20%,我们应该如何求出最终的权重结果呢?

解决方案如下:

代码语言:javascript复制
var dis = {
  math: 0.5,
  chinese: 0.3,
  english: 0.2
}

var sum = result.reduce(function (prev, cur) {
  return cur.score   prev;
}, -10);

var qsum = result.reduce(function (prev, cur) {
  return cur.score * dis[cur.subject]   pre;
}, 0)

console.log(sum, qsum);

0 人点赞