用 reduce 将扁平数组转树形结构的核心是:先构建 id 映射表,再按 parentid 挂载子节点到父节点的 children 数组中;需统一 parentid 类型、初始化 children 为空数组,并将根节点(如 parentid 为 null)单独收集。

用 reduce 把扁平数组转成树形结构,核心是:**按 parent ID 找父节点,把当前项 push 到对应 children 数组里,同时维护一个 ID → 节点的映射表,确保子节点能正确挂载**。
明确数据格式和根节点识别方式
扁平数组通常含 id、parentId(或 parent_id)、name 等字段。根节点的 parentId 一般为 null、undefined、0 或空字符串。需先确认你的数据中根节点的判定条件。
- 常见根标识:
item.parentId === null、item.parentId === 0、!item.parentId - 建议统一处理:提前将
parentId转为数字或字符串,避免类型不一致导致匹配失败
用 reduce 构建 ID 映射 + 挂载 children
不能只靠 reduce 返回树,而是用它遍历一次,生成两个东西:一个所有节点的映射对象(id → node),另一个只存根节点的数组。过程中动态给父节点的 children 推入子节点。
- 初始化时设
{ map: {}, roots: [] }作为 reduce 的初始值 - 每轮遍历:先将当前节点存入
map[id] = {...item, children: []} - 若它是根节点(如
!item.parentId),推入roots;否则找到map[item.parentId],把当前节点加进它的children - 注意:父节点可能还没遍历到,所以要确保父节点也初始化(哪怕暂时没 children)
完整可运行示例代码
假设数据如下:
const list = [{ id: 1, name: '首页', parentId: null },
{ id: 2, name: '产品', parentId: null },
{ id: 3, name: 'Web端', parentId: 2 },
{ id: 4, name: 'App端', parentId: 2 },
{ id: 5, name: '登录页', parentId: 3 }
];
转换逻辑:
const tree = list.reduce((acc, item) => {
const node = { ...item, children: [] };
acc.map[item.id] = node;
if (item.parentId == null) {
acc.roots.push(node);
} else {
const parent = acc.map[item.parentId];
if (parent) parent.children.push(node);
}
return acc;
},
{ map: {}, roots: [] }
).roots;
结果 tree 就是根节点组成的数组,已带完整嵌套结构。
注意事项与常见坑
- 顺序无关性:该方法不要求数据按层级顺序排列,因为靠 ID 映射关联,即使子在父前面也能正确挂载
-
children 初始化必须一致:每个节点都要有
children: [],否则后续 push 会报错 -
parentId 类型要统一:后端可能传字符串 "1",而 JS 中用数字 1 查,会导致找不到父节点,建议做
String(item.parentId)或Number()标准化 - 避免重复引用:不要直接 push 原对象再修改,应结构赋值或深拷贝,防止副作用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











