一、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);