You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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);

关键说明

  1. 层级精准传递:通过currentLayer参数直接记录当前层级,子节点层级为currentLayer + 1,完全匹配数据的嵌套深度。
  2. 父信息直接复用:递归时传入父节点的id和display,无需从结果数组中反向查找,避免大数据量下的性能损耗。
  3. 唯一ID生成:根节点ID直接用display,子节点按照${层级}-父display-当前display规则拼接,确保全局唯一。
  4. 边界处理:添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:18:22