标准答案
- reduce 接收 callback 和可选 initialValue。
- callback 接收 accumulator、currentValue、index 和原数组。
- 传入 initialValue 时,accumulator 初始为该值,并从第一个元素开始遍历。
- 未传 initialValue 时,要找到第一个存在的数组元素作为初始 accumulator。
- 空数组且未传 initialValue 时应该抛出 TypeError。
题目解析
reduce 最容易写错的是初始值。很多简化实现默认拿 array[0],但稀疏数组可能第 0 位不存在,空数组也需要抛错。
reduce 是很多数组方法的底层表达能力来源,可以用来做求和、分组、索引映射和管道组合。但生产代码里不要为了炫技把简单逻辑都写成难读的 reduce。
实现时还要区分“有没有传 initialValue”,不能用 initialValue 是否为 truthy 判断,因为 0、false、空字符串都可能是合法初始值。
代码示例
下面的实现用 arguments.length 判断是否传入初始值。
JavaScript
function reduce(array, callback, initialValue) {
if (array == null) {
throw new TypeError('array is null or undefined')
}
if (typeof callback !== 'function') {
throw new TypeError('callback must be a function')
}
const source = Object(array)
const length = source.length >>> 0
let index = 0
let accumulator
if (arguments.length >= 3) {
accumulator = initialValue
} else {
while (index < length && !(index in source)) {
index += 1
}
if (index >= length) {
throw new TypeError('Reduce of empty array with no initial value')
}
accumulator = source[index]
index += 1
}
for (; index < length; index += 1) {
if (index in source) {
accumulator = callback(accumulator, source[index], index, source)
}
}
return accumulator
}常见误区
- 用 initialValue || array[0] 判断初始值,导致 0、false、空字符串被误判。
- 空数组未传初始值时没有抛错。
- 没有跳过稀疏数组不存在的索引。