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 变成一个值的时候,或多或少,必然丢失了一些信息。