JavaScript ES6如何遍历嵌套层级不一致的combinedPorts数组
问题描述
我有如下结构的数组,其中包含键名为combinedPorts的嵌套数组。当所有对象的combinedPorts嵌套层级一致时,我可以直接用ES6的.map方法遍历并展示对应属性;但在示例数据中,第一个对象的combinedPorts键共嵌套3层,第二个对象的combinedPorts键仅嵌套2层。请问当不同对象的combinedPorts嵌套深度存在差异时,应当如何遍历该键对应的内容?
示例数据如下:
[ { "name": "Test Source", "combinedPorts": [ { "name": "PortGroup_1", "templateId": "edfb5b72ec580b129465ea0e8029bad3", "type": "SourcePorts", "combinedPorts": [ { "name": "Source_1", "templateId": "2355fc02e18cd48c6b487aa8b6f75959", "type": "SourcePorts", "combinedPorts": [ { "name": "Sami_TestSource", "templateId": "0007ad49ea9b02b309a1248592a01981", "type": "SourcePorts" }, ], } ], } ], "portGroupInfo": [] }, { "name": "Test Source", "combinedPorts": [ { "name": "PortGroup_1", "templateId": "edfb5b72ec580b129465ea0e8029bad3", "type": "SourcePorts", "combinedPorts": [ { "name": "Source_1", "templateId": "2355fc02e18cd48c6b487aa8b6f75959", "type": "SourcePorts" } ], } ], "portGroupInfo": [] } ]
解决方案
处理这种层级不固定的嵌套结构,别硬写固定层数的.map,写个递归遍历函数就行,逻辑非常简单:只要当前节点存在非空的combinedPorts数组,就继续往下遍历,直到节点没有下一层combinedPorts就停止,天然适配不同对象的嵌套深度差,不需要提前知道每个对象嵌了多少层。
基础遍历实现
这个版本可以遍历到每一层的所有节点,你可以在回调里写自己的渲染、数据处理逻辑:
/** * 递归遍历combinedPorts节点 * @param {Array} nodes 待遍历的节点数组 * @param {number} level 当前遍历层级,从0开始 * @param {Function} callback 每个节点的处理函数,接收当前节点和层级作为参数 */ function traverseCombinedPorts(nodes, level = 0, callback) { nodes.forEach(node => { // 先处理当前节点,不管它有没有子节点 callback(node, level); // 存在非空子节点数组就递归进下一层 if (Array.isArray(node.combinedPorts) && node.combinedPorts.length) { traverseCombinedPorts(node.combinedPorts, level + 1, callback); } }); } // 调用示例 const yourData = []; // 替换成你自己的原始数组 yourData.forEach(topItem => { if (Array.isArray(topItem.combinedPorts)) { traverseCombinedPorts(topItem.combinedPorts, 0, (port, level) => { // 这里写你的业务逻辑,比如渲染列表、打印信息 console.log(`第${level}层端口:`, port.name, port.type); }); } });
只取最底层叶子节点
如果你不需要中间的分组节点,只想拿到最内层没有子combinedPorts的实际端口,可以用这个版本,直接返回所有叶子节点的扁平数组:
function getLeafPortList(nodes, res = []) { nodes.forEach(node => { const hasChild = Array.isArray(node.combinedPorts) && node.combinedPorts.length; if (hasChild) { getLeafPortList(node.combinedPorts, res); } else { res.push(node); } }); return res; } // 调用示例 const allLeafPorts = []; yourData.forEach(topItem => { if (Array.isArray(topItem.combinedPorts)) { allLeafPorts.push(...getLeafPortList(topItem.combinedPorts)); } });
补充:如果你的数据有可能出现循环引用(极端场景下子节点指回上层节点),可以加一个Set存已经遍历过的节点id,避免死循环,常规业务端口数据一般不会有这种问题,按需添加即可。
内容的提问来源于stack exchange,提问作者Test1234
相关产品推荐
相关产品推荐

