如何遍历JavaScript对象数组构建树形层级结构?
嘿,我来帮你搞定把JavaScript对象数组转成树形层级结构的问题!其实这个需求的核心思路很清晰,咱们一步步来实现:
实现思路与步骤
首先得明确你的原始数据结构——一般来说,每个对象都会有唯一标识(比如id)和父节点标识(比如parentId),根节点的parentId可以设为null或者特定值(比如0)。我先假设你的输入数据长这样:
const rawData = [ { id: 1, name: 'Root Parent 01', parentId: null }, { id: 2, name: 'Root Parent 02', parentId: null }, { id: 3, name: 'Root Parent 03', parentId: null }, { id: 4, name: 'Child 01', parentId: 3 }, { id: 5, name: 'Child 02', parentId: 3 }, { id: 6, name: 'Child 03', parentId: 3 }, { id: 7, name: 'Root Parent 04', parentId: null }, { id: 8, name: 'Child 04', parentId: 7 }, { id: 9, name: 'Child 05', parentId: 7 }, { id: 10, name: 'Child 06', parentId: 7 }, { id: 11, name: 'Child 07', parentId: 7 }, { id: 12, name: 'Child 08', parentId: 7 }, { id: 13, name: 'Child 09', parentId: 7 }, { id: 14, name: 'Child 10', parentId: 7 }, { id: 15, name: 'Child 11', parentId: 7 }, { id: 16, name: 'Root Parent 05', parentId: null }, { id: 17, name: 'Child 12', parentId: 16 }, { id: 18, name: 'Child 13', parentId: 16 }, { id: 19, name: 'Child 14', parentId: 16 }, { id: 20, name: 'Child 15', parentId: 16 }, { id: 21, name: 'Child 16', parentId: 16 }, { id: 22, name: 'Child 17', parentId: 16 }, { id: 23, name: 'Child 19', parentId: 16 }, { id: 24, name: 'Child 18', parentId: 23 } ];
1. 构建节点映射表
首先我们需要一个快速查找节点的映射表(用Map或者普通对象都行),同时给每个节点初始化一个children数组,用来存放子节点:
const nodeMap = new Map(); // 遍历原始数据,把每个节点存入映射表,并初始化children rawData.forEach(item => { nodeMap.set(item.id, { ...item, children: [] }); });
这个映射表的好处是能让我们以O(1)的时间复杂度快速定位任意节点,整个构建过程的时间复杂度是O(n),效率很高
2. 组装树形结构
接下来遍历所有节点,把非根节点挂载到对应的父节点的children数组里,根节点直接加入顶层树形数组:
const tree = []; rawData.forEach(item => { const currentNode = nodeMap.get(item.id); if (item.parentId === null) { // 根节点直接加入树形结构顶层 tree.push(currentNode); } else { // 找到父节点,将当前节点加入父节点的children const parentNode = nodeMap.get(item.parentId); if (parentNode) { // 做个容错,避免父节点不存在的情况 parentNode.children.push(currentNode); } } });
3. 验证树形结构(打印输出)
为了确认结果符合你的预期,我们可以写一个递归函数来打印树形结构:
function printTree(nodes, indent = '') { nodes.forEach(node => { console.log(`${indent}${node.name}`); // 如果有子节点,递归打印,增加缩进 if (node.children.length > 0) { printTree(node.children, indent + '---'); } }); } // 调用打印函数 printTree(tree);
运行这段代码后,控制台输出就会和你预期的结构完全一致:
Root Parent 01 Root Parent 02 Root Parent 03 ---Child 01 ---Child 02 ---Child 03 Root Parent 04 ---Child 04 ---Child 05 ---Child 06 ---Child 07 ---Child 08 ---Child 09 ---Child 10 ---Child 11 Root Parent 05 ---Child 12 ---Child 13 ---Child 14 ---Child 15 ---Child 16 ---Child 17 ---Child 19 ------Child 18
注意事项
- 如果你的根节点标识不是
null(比如用0或者''),记得修改判断条件item.parentId === null为对应的标识; - 如果原始数据中存在父节点不存在的情况,上面的代码会自动跳过这些节点,你也可以根据需求添加错误提示;
- 如果你不想修改原始对象,记得用扩展运算符
{ ...item }创建副本,避免污染原数据。
内容的提问来源于stack exchange,提问作者Cody Tolene
相关产品推荐
相关产品推荐

