原生的reduce方法只适用于数组,且方向固定为从左向右。
underscore中的reduce与reduceRight分别支持两个方向的迭代,且支持对对象的操作。
_.reduce = _.foldl = _.inject = createReduce(1);
_.reduceRight = _.foldr = createReduce(-1);
其底层实现均为createReduce方法。
createReduce
//dir决定迭代方向,-1为从右向左,1为从左向右
var createReduce = function(dir) {
// Wrap code that reassigns argument variables in a separate function than
// the one that accesses `arguments.length` to avoid a perf hit. (#1991)
//这里是迭代的核心函数
var reducer = function(obj, iteratee, memo, initial) {
//处理数组与对象的不同
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
//迭代方向
index = dir > 0 ? 0 : length - 1;
//是否提供最初与数组或对象进行迭代的数据
if (!initial) {
memo = obj[keys ? keys[index] : index];
//需要将起始位置向迭代方向移动一位
index += dir;
}
//迭代
for (; index >= 0 && index < length; index += dir) {
var currentKey = keys ? keys[index] : index;
memo = iteratee(memo, obj[currentKey], currentKey, obj);
}
return memo;
};
return function(obj, iteratee, memo, context) {
//initial变量标识是否提供最初的迭代数据
var initial = arguments.length >= 3;
return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
};
};