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 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);   // 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的本质就是:

降维


aaron_lawliet
178 声望2 粉丝