javascript中的Array.reduce方法

一、概述

参考:-MDN web docs

Array.prototype.reduce()

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。reduce是ES5中新增的又一个数组逐项处理方法

const arr = [1, 2, 3, 4];
const result = arr.reduce((accumulator, currentValue) => accumulator + currentValue)
1 + 2 + 3 + 4
console.log(result) // 10

Array.reduce(reducer) reducer函数接收4个参数:

  1. accumulator(acc)累计器
  2. currentValue(cur)当前值
  3. curerntIndex(idx)当前索引
  4. sourceArray(src)源数组

二、语法

reduce的使用方法:
arr.reduce(callback(acc, cur[, idx[, src]])[,initalValue])
参数:

callback: 执行数组中每个值的函数(如果没有初始值initalValue则第一个除外),其有四个参数:

acc:累计器累计回调的返回值;踏实上一次调用回调时返回的累积值,或者initalValue
cur:数组中正在处理的元素
idx:(可选)数组中正在处理的当前元素的索引,(如果提供了initialValue,则起始索引号为0,否则从索引1起始。)
src:(可选)调用reduce的数组

initalValue:(可选)作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则使用数组中的第一个元素。 ps:在没有初始值的空数组上调用 reduce 将报错。

三、reduce如何运行

比如运行如下reduce代码:

[0, 1, 2, 3, 4].reduce(function(acc, cur, idx, arr) {
    return acc + cur
})

callback被调用了四次,每次调用和返回值如下表:

callback acc cur idx arr return value
1 call 0 1 1 [0, 1, 2, 3, 4] 1
2 call 1 2 2 [0, 1, 2, 3, 4] 3
3 call 3 3 3 [0, 1, 2, 3, 4] 6
4 call 6 4 4 [0, 1, 2, 3, 4] 10

如果为reduce()提供第二个参数,其运行结果如下:

[0, 1, 2, 3, 4].reduce(function(acc, cur, idx, arr) {
    return acc + cur
}, 10)
callback acc cur idx arr return value
1 call 10 0 0 [0, 1, 2, 3, 4] 10
2 call 10 1 1 [0, 1, 2, 3, 4] 11
3 call 11 2 2 [0, 1, 2, 3, 4] 13
4 call 13 3 3 [0, 1, 2, 3, 4] 16
5 call 16 4 4 [0, 1, 2, 3, 4] 20

四、reduce与map和forEach的区别

  • reduce() 方法将会对数组元素从左到右依次执行reducer函数,然后返回一个累计的值
  • forEach() 方法对数组的每个元素执行一次给定的函数
  • map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。

实现数组求和的例子:

// reduce 实现
var arr = [1, 2, 3, 4];
var sum = arr.reduce((acc, cur) => acc + cur);
// sum = 10

//forEach 实现
var sum = 0 ;
var arr = [1, 2, 3, 4];
arr.forEach(function(cur){
    sum += cur;
})
// [1, 3, 6, 10]
// sum = 10

// map实现
var arr = [1, 2, 3, 4];
var sum = 0;
arr.map(function(cur) {
    return sum += cur;
})
// return [1, 3, 6, 10]
// sum = 10

五、使用例子

按顺序执行Promise:

function run PromisebySeq(arr, input) {
    return arr.reduce(
        (promiseChain, curPromise) => promiseChain.then(curPromise) ,
        Promise.resolve(input)
    )
}

// promise function 1
function p1(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 5);
  });
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 2);
  });
}

// function 3  - will be wrapped in a resolved promise by .then()
function f3(a) {
 return a * 3;
}

// promise function 4
function p4(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 4);
  });
}

const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10)
  .then(console.log);

六、Polyfill

if(!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(callback) {
      if(this === null) {
        throw new TypeError('null can not call')
      }
      if(typeof callback !== 'function') {
        throw new TypeError('callback is not a function')
      }
      var o = Object(this);

      var len = o.length >>> 0;
      var k = 0;
      var value;
      if(arguments.length >= 2) {
        value = arguments[1]
      } else {
        while(k < len && !(k in o)) {
          k++
        }
        if(k >= len) {
          throw new TypeError('empt array')
        }
        value = o[k++];
      }
      while(k < len) {
        if(k in o) {
          value = callback(value, o[k], k, o);
        }
        k++
      }
      return value;
    }
  })
}