reduce函数是JavaScript的数组函数中,功能比较强大的函数。但是大部分博文对reduce函数的解释都是比较和基础。

reduce的基础用法

我们先来看看reduce的基础用法,由于reduce的基础用法,在MDN里有比较详尽的解释,所以建议各位直接去看MDN

JavaScript | MDN | Array.prototype.reduce()
里面有几个比较典型的例子

例1.数组去重:

var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];var myOrderedArray = myArray.reduce(function (accumulator, currentValue) {  if (accumulator.indexOf(currentValue) === -1) {    accumulator.push(currentValue);  }  return accumulator}, [])console.log(myOrderedArray);

实际上,如果不用Set,咋一看可以用filter实现,但是由于filter拿不到迭代的结果array,所以用filter或者forEach、map实现都需要借助外部定义的数组,比如

var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];var resultArray = [];myArray.forEach(item => {    if(resultArray.indexOf(item) === -1){        resultArray.push(item);    }})

例2.迭代使用Promise

function runPromiseInSequence(arr, input) {  return arr.reduce(    (promiseChain, currentFunction) => promiseChain.then(currentFunction),    Promise.resolve(input)  );}// promise function 1function p1(a) {  return new Promise((resolve, reject) => {    resolve(a * 5);  });}// promise function 2function 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 4function p4(a) {  return new Promise((resolve, reject) => {    resolve(a * 4);  });}const promiseArr = [p1, p2, f3, p4];runPromiseInSequence(promiseArr, 10)  .then(console.log);   // 1200

reduce的特点就是在迭代过程中,可以使用之前的迭代结果

所以我们得出第一个结论:

迭代过程中,需要使用到迭代结果的,适合使用reduce
反之,如果迭代过程中,不需要使用迭代结果,那么Array.prototype上的其他函数,完全可以胜任任何逻辑。

例3:把originArray数组变成一个一维数组

let originArray = [1,[2,3],[4,[5,6,[7,8],9],10,[11,12,[13,14],15],16],17];function smoothArray(array){    return array.reduce((resultArray, currentValue) => {        let concatArray;        if(Array.isArray(currentValue)){            concatArray = smoothArray(currentValue);        }else{            concatArray = [currentValue];        }        return resultArray.concat(concatArray);    }, [])}smoothArray(originArray);// 结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]

本例中,我们通过递归的方式,将N维数组originArray降维变成了一维数组。
显而易见地,如果要把originArray变成一个0维数组(0维数组就是一个值),通过这个方法也是可行的。变成0维数组(一个值)的方式,可以是累加、累乘、累减等方法。在这里,用什么方法是不重要的,重要的是reduce干了什么、什么是reduce的本质。

什么是reduce的本质?

抽象地,reduce的调用者一定是一个数组,这个数组至少是一个一维数组。得到的结果是一个值,这个值可能是数组,可能是对象,可能是JavaScript基础类型中的一个值。
reduce做的事情,是:
数组 => 一个值
我们和Array.prototype上的其他函数做个比较,可以发现,map、forEach、filter一定返回一个数组;includes、find、findIndex必然返回一个值;reduce做的,是将一个高维度的东西,“压缩”成一个值的过程。
读过《三体》的朋友,一定对《三体III》中描述的四维文明、以及太阳系二维化的情节有印象。降维的过程,几乎必然伴随着信息的丢失。reduce也不例外。当你将一个数组通过reduce变成一个值的时候,或多或少,必然丢失了一些信息。

最后,总结一下reduce的本质就是:

降维