如何在JavaScript中按层级遍历对象并获取层级信息
问题描述
我正在将嵌套数据对象转换为数组,以供UI库展示数据间的关系。
原始数据
// assume that all object key is unique { "top":{ "test":{ "hello":"123" }, "test2":{ "bye":"123", "other":{ ... ... ... } } } }
最初期望结果
[ { id:"top", parent: null, }, { id:"test", parent: "top", }, { id:"hello", parent: "test", }, { id:"test2", parent: "top", }, ]
初始实现代码
const test = [] const iterate = (obj, parent = null) => { Object.keys(obj).forEach(key => { const id = typeof obj[key] === 'object' ? key : obj[key] const loopObj = { id, parent } test.push(loopObj) if (typeof obj[key] === 'object') { iterate(obj[key], id) } }) } iterate(data) console.log(test) // Done!!
新需求:添加层级与唯一ID
现在UI库需要层级信息,且不同层级可能有重复key,需要生成唯一ID,示例如下:
含重复key的原始数据
// The key name maybe duplicated in different layer { "top":{ // Layer 1 "test":{ // Layer 2 "hello":"123", // Layer 3 "test":"123" // Layer 3 // Maybe many many layers... } } }
期望的新结果
[ { id:"top", display:"0-top", parent: null, layer: 0 }, { id: "1-top-test", // 唯一ID格式:`${layer}-${parentDisplay}-${display}` display:"test", parent: "0-top", parentDisplay: "top", layer: 1 }, { id: "2-test-test", display:"test", parent: "1-top-test", parentDisplay: "test", layer: 2 } ]
我尝试过在外部定义let count = 0并在调用iterate时自增,但这是按对象检测计数而非层级计数。原始数据可能非常庞大,修改原始结构或每次循环查找父ID都不是理想方案,求可行解决方案。
解决方案
核心思路是在递归函数中直接传递当前层级和父节点的关键信息,这样每一层都能直接生成所需字段,无需后续查找或修改原始数据,兼顾性能与准确性。
优化后的代码
const result = []; const iterate = (obj, parentInfo = { parentId: null, parentDisplay: null, currentLayer: 0 }) => { const { parentId, parentDisplay, currentLayer } = parentInfo; Object.keys(obj).forEach(key => { // 排除null(typeof null === 'object'会干扰判断) const isObject = typeof obj[key] === 'object' && obj[key] !== null; const display = key; // 生成唯一ID:根节点直接用display,子节点按规则拼接 const id = parentId === null ? display : `${currentLayer}-${parentDisplay}-${display}`; // 组装当前节点数据 const node = { id, display, parent: parentId, parentDisplay: parentDisplay, layer: currentLayer }; result.push(node); // 递归处理子节点,层级+1,传递当前节点的信息作为父参数 if (isObject) { iterate(obj[key], { parentId: id, parentDisplay: display, currentLayer: currentLayer + 1 }); } }); }; // 调用示例 const data = { "top":{ "test":{ "hello":"123", "test":"123" } } }; iterate(data); console.log(result);
关键说明
- 层级精准传递:通过
currentLayer参数直接记录当前层级,子节点层级为currentLayer + 1,完全匹配数据的嵌套深度。 - 父信息直接复用:递归时传入父节点的
id和display,无需从结果数组中反向查找,避免大数据量下的性能损耗。 - 唯一ID生成:根节点ID直接用
display,子节点按照${层级}-父display-当前display规则拼接,确保全局唯一。 - 边界处理:添加
obj[key] !== null判断,避免将null误判为对象进行递归。
输出结果验证
针对示例中含重复key的数据,运行代码后会输出:
[ { id: 'top', display: 'top', parent: null, parentDisplay: null, layer: 0 }, { id: '1-top-test', display: 'test', parent: 'top', parentDisplay: 'top', layer: 1 }, { id: '2-test-hello', display: 'hello', parent: '1-top-test', parentDisplay: 'test', layer: 2 }, { id: '2-test-test', display: 'test', parent: '1-top-test', parentDisplay: 'test', layer: 2 } ]
完全符合需求,且递归过程无额外性能开销,适合处理大规模嵌套数据。
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

