JS数组reduce方法详解和高级技巧

基本概念

reduce()方法接受一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值

reduce为数组中的每个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值)

当前元素值,当前索引,调用reduce的数组

语法

arr.reduce(callback,[initialValue])

  •     callback(执行数组中每个值的函数,包含四个参数)        

  1.  previousValue(上一次调用回调函数返回的值,或者是提供的初始值(initialValue))
  2. currentValue(数组中当前被处理的元素)
  3. index(当前元素在数组中的索引)
  4. array(调用reduce的数组)           
  •     initialValue(作为第一次调用callback的第一个参数,也就是初始值)

简单应用

例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}


参考:

JS进阶篇--JS数组reduce()方法详解及高级技巧


你可能感兴趣的:(JS数组reduce方法详解和高级技巧)