用 reduce 处理嵌套对象聚合,关键在于让累加器随深度动态演进:其形态须匹配目标结构(如分类汇总对象或树状统计对象),配合递归、Object.entries 动态遍历及纯函数式更新(返回新对象而非修改原值)。

用 reduce() 处理嵌套对象的聚合,关键不在“炫技”,而在于把每层结构拆解成可累积的中间状态——不是一次性压平所有层级,而是让累加器(accumulator)随遍历深度动态演进。
明确累加器的形态:它得“长成数据的样子”
面对嵌套对象(比如带 categories → subcategories → items 的销售数据),累加器不能只是数字或字符串。它应是目标聚合结构的雏形:
- 若要按 category 汇总销售额,累加器可以是
{ categoryA: 1200, categoryB: 850 } - 若要生成带子项统计的树状结构,累加器就该是类似
{ name: 'Electronics', total: 5200, subcategories: [ ... ] }的对象 - 切忌用空对象
{}开始却没想清后续怎么塞值——reduce 不会自动帮你推导结构
递归 + reduce:一层一层“收口”
对含 children 或 items 数组的嵌套对象,reduce 本身不递归,但你可以让它调用自身:
- 主 reduce 遍历顶层数组,对每个 item 调用一个内部 reduce 或递归函数处理其子集
- 子级处理结果作为值,合并进当前层累加器(例如:
acc[item.id] = { ...item, childrenStats: getChildStats(item.children) }) - 示例场景:统计每个部门下各职级人数及平均薪资,需先算小组,再向上汇总——每一层 reduce 返回一个含
count和avgSalary的对象,上层直接累加
用 Object.keys() / for...in 配合 reduce 处理未知键名
当嵌套对象的属性名不固定(如用户自定义字段、多语言 key),不能写死 obj.name。此时可结合 Object.keys() 提取路径:
- 先用
Object.entries(obj)转为[[key, value], ...]数组,再用 reduce 遍历 - 对每个
[key, value]判断typeof value === 'object' && value !== null && !Array.isArray(value),决定是否深入 - 这样就能在不预设 schema 的前提下,做“字段级”聚合(比如统计所有字符串字段长度总和、所有数字字段最大值)
避免副作用:每次返回新对象,别改原 accumulator
reduce 的纯函数特性容易被破坏——尤其在嵌套时误用 acc[key] = newValue 直接赋值:
- 这会污染前序迭代的累加器引用,导致错误累积
- 正确做法是始终返回新对象:
{ ...acc, [key]: newValue }或用Object.assign({}, acc, { [key]: newValue }) - 对深层嵌套,可用结构克隆工具(如
structuredClone)或手动展开,确保变更只影响当前层级











