reduce()方法接受一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值
reduce为数组中的每个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值)
当前元素值,当前索引,调用reduce的数组
arr.reduce(callback,[initialValue])
简单应用
例1
var item = [10, 120, 1000];
var reducer = function (sumSoFar, item) { return sumSoFar + item};
var total = items.reduce(reducer, 0);
console.log(total); // 1130
// 也可以这样写
var arr = [10, 120, 1000];
var sum = arr.reduce(function (prev, curr) { return prev + curr }, 0)
console.log(sum) // 1130
可以看出,reduce函数根据初始值0,不断的进行叠加,完成最简单的总和的实现。
reduce函数的返回结果类型和传入的初始值相同,上个实例中初始值为Number类型,同理,初始值也可以是object类型
例2
var items = [10, 120, 1000];
// our reducer function
var reducer = function (sumSoFar, item) {
sumSoFar.sum = sumSoFar.sum + item;
return sumSoFar;
}
var total = items.reduce(reducer, {sum: 0});
console.log(total) // {sum: 1130}
进阶应用
使用reduce方法可以完成多维度的数据叠加,如上例中的初始值是{sum:0},这仅仅是一个维度的操作,如果涉及到了多个属性的叠加,如{sum: 0,totalInEuros: 0,totalInYen: 0},则需要相应的逻辑进行处理
上面的方法中个,采用分而治之的方法,即将reduce函数第一个参数callback封装为一个数组,由数组中的每一个函数单独进行叠加并完成reduce操作。所有的一切通过一个manager函数来管理流程和传递初始参数。
var manageReducers = function (reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function (nextState, key) {
reducers[key](state, item);
return state;
},{});
}
};
// Object.keys(),返回一个数组,包括对象自身的所有可枚举属性的键名
上面就是manager函数的实现,它需要reduces对象作为参数,并返回一个callback类型的函数,作为reduce的第一个参数。在该函数内部,则执行多维的叠加工作(Object.keys())
通过这种分治的思想,可以完成目标对象多个属性的同时叠加,完整代码如下:
var reducers = {
totalInEuros: function (state, item) {
return state.euros += item.price * 0.897424392;
},
totalInYen: function (state, item) {
return state.yens += item.price * 113.852;
}
};
var manageReducers = function (reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function (nextState, key) {
reducers[key](state, item);
return state;
},{});
}
};
// Object.keys(reducers) = [totalInEuros, totalInYen]
var bigTotalPriceReducer = manageReducers(reducers);
var initialState = {euros: 0, yens: 0};
var items = [{price: 10}, {price: 120},{price: 1000}];
var totals = item.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
下一个例子
某同学的期末成绩如下表示
var result = [
{
subject: 'math',
score: 88
},
{
subject: 'chinese',
score: 95
},
{
subject: 'english',
score: 80
}
];
如何求该同学的总成绩?
var sum = result.reduce(function (prev, curr) {
return curr.score + prev;
}, 0);
假设该同学因为违纪被处罚,会根据总成绩扣10分,只需将初始值设置为-10即可
var sum = result.reduce(function (prev, curr) {
return curr.score + prev;
}, -10)
解决方案如下:
var dis = {
math: 0.5,
chinese: 0.3,
english: 0.2
};
var sum = result.reduce(function (prev, curr) {
return curr.score + prev;
}, -10);
var qsum = result.reduce(function (prev, curr) {
return curr.score * dis[curr.subject] + prev;
}, 0);
// JS 对象取值的方法有两种
var obj = {a: 1, b: 4};
第一种
obj.a // 1
第二种
obj['a'] // 1
第一种性能上优于第二种,但是第一种不能动态取值,第二种中括号里面可以是变量,也可以配合模板字符串使用`${key}`
var c = 'a';
obj[c] // 1
再看一个例子,如何知道一串字符串中每个字母出现的次数?
var arrString = 'abcdaabddcca';
arrString.split('').reduce(function (prev, curr) {
prev[curr] ? prev[curr]++ : prev[curr] = 1;
return prev;
}, []);
// [a: 4, b: 2, c: 3, d: 3]
var prev = [];
var curr = 'a';
prev[curr] = 1;
prev // [a: 1]
prev.length // 0
prev[curr]++
prev // [a: 2]
如果第二个参数是对象,就可以数组对象之间进行转化
var arrString = 'abcdaabddcca';
arrString.split('').reduce(function (prev, curr) {
prev[curr] ? prev[curr]++ : prev[curr] = 1;
return prev;
}, {});
{a: 4, b: 2, c: 3, d: 3}
参考: