js之reduce方法解析
reduce 是 JavaScript 数组中最灵活也最有表现力的方法之一。你可以用它实现很多功能,比如:
✅ 常见用途举例:
1. 数组求和
[1, 2, 3, 4].reduce((acc, n) => acc + n, 0) // 10
2. 数组转对象
const arr = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
const obj = arr.reduce((acc, item) => {
acc[item.id] = item.name
return acc
}, {})
console.log(obj)
// { 1: 'Alice', 2: 'Bob' }
3. 统计某个值出现的次数
const colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
const count = colors.reduce((acc, color) => {
acc[color] = (acc[color] || 0) + 1
return acc
}, {})
console.log(count)
// { red: 2, blue: 3, green: 1 }
4. 扁平化数组
const nested = [[1, 2], [3, 4], [5]]
const flat = nested.reduce((acc, arr) => acc.concat(arr), [])
console.log(flat) // [1, 2, 3, 4, 5]
📌 小技巧:避免副作用
reduce 中如果要操作对象或数组,最好返回一个新的对象/数组,避免修改 acc 引起难以发现的副作用。
需要的时候也可以嵌套 reduce,结合 map/filter 更强大。如果想用在 Vue/Nuxt 的 computed 中,也非常高效且响应式友好。
reduce 的第二个参数就是:初始值(initial value)
📌 举个最简单的例子:
const arr = [1, 2, 3, 4]
const sum = arr.reduce((acc, item) => acc + item, 0)
// ↑ ↑
// 初始值 acc 当前项 item
console.log(sum) // 10
这里 0 就是初始值,acc 从 0 开始累加。
🚨 如果没有提供初始值,会发生什么?
当你 不传第二个参数,reduce 会默认使用数组的 第一个元素作为初始值,从第二个元素开始循环。
示例:
const arr = [1, 2, 3, 4]
const sum = arr.reduce((acc, item) => acc + item)
// 初始 acc = 1(arr[0])
// 从 item = 2 开始
console.log(sum) // 10
虽然结果是一样的,但:
❗为什么推荐总是提供初始值?
更安全,避免空数组报错:
[].reduce((acc, item) => acc + item, 0) // ✅ 返回 0 [].reduce((acc, item) => acc + item) // ❌ TypeError: Reduce of empty array with no initial value更清晰,一眼看出你希望累加/合并成哪种类型的值(数值、对象、数组等):
arr.reduce((acc, item) => { ... }, {}) // 初始是一个对象 arr.reduce((acc, item) => { ... }, []) // 初始是一个数组 arr.reduce((acc, item) => { ... }, '') // 初始是一个字符串
✅ 总结:
reduce(callback, initialValue)的第二个参数就是 初始值。- 建议:总是显式传初始值,更加健壮、清晰、可维护。特别是在你处理对象或空数组的时候。
