reduce本身不自动遍历分组,而是通过累加器手动构建分组结构:以属性值为key、元素数组为value生成对象;可用Object.create(null)防原型污染,或用Map支持任意类型key。

JavaScript 中 reduce 本身不“遍历分组”,而是通过累加器(accumulator)手动构建分组结构,核心是把数组元素按某个属性值归类到对象或 Map 的不同键下。
用 reduce 按属性名分组为对象
最常用方式:以目标属性值为 key,对应元素组成的数组为 value,返回一个分组对象。
例如按 category 分组:
const items = [
{ id: 1, name: '苹果', category: '水果' },
{ id: 2, name: '香蕉', category: '水果' },
{ id: 3, name: '胡萝卜', category: '蔬菜' }
];
const grouped = items.reduce((acc, item) => {
const key = item.category;
if (!acc[key]) acc[key] = [];
acc[key].push(item);
return acc;
}, {});
// 结果:
// {
// '水果': [{ id: 1, name: '苹果', category: '水果' }, ...],
// '蔬菜': [{ id: 3, name: '胡萝卜', category: '蔬菜' }]
// }
更安全的写法(避免原型污染)
用 Object.create(null) 初始化累加器,防止 key 碰巧是 toString、constructor 等原型方法名:
立即学习“Java免费学习笔记(深入)”;
- 替换
{}为Object.create(null) - 用
hasOwnProperty或Object.prototype.hasOwnProperty.call(acc, key)判断 key 是否存在(可选,但更严谨)
支持多级嵌套或动态属性路径
如果要按深层属性(如 user.profile.city)分组,可封装一个取值函数:
const get = (obj, path) => path.split('.').reduce((cur, p) => cur?.[p], obj);
const groupedByCity = data.reduce((acc, item) => {
const key = get(item, 'user.profile.city') || 'unknown';
if (!acc[key]) acc[key] = [];
acc[key].push(item);
return acc;
}, Object.create(null));
用 Map 替代普通对象(适合任意类型 key)
当分组依据不是字符串/数字(比如对象、Symbol、函数),普通对象无法胜任,改用 Map:
- 初始化累加器为
new Map() - 用
map.get(key)获取已有数组,用map.set(key, newArray)更新 - 最后可用
Object.fromEntries(map)转为普通对象(如需)
const groupedMap = items.reduce((map, item) => {
const key = item.category;
const list = map.get(key) || [];
list.push(item);
map.set(key, list);
return map;
}, new Map());
不复杂但容易忽略细节,关键是理解 reduce 是“自己造桶、自己放东西”,而不是自动分组。


















