如何将嵌套JSON对象转换为树形结构对象数组?
树形结构JSON转换实现的优化建议
需求说明
需要将层级嵌套的JSON结构转换为包含id、name、children字段的树形对象数组格式,以下是原始数据、目标格式及当前实现代码:
原始JSON结构
let data = { "Branches": { "Marketing": { "Sub-Branches": { "Digital Marketing": { "Sub-Branches": { "Search Engine Optimization": null, "Social Media Marketing": null } }, "Traditional Marketing": { "Sub-Branches": { "Print Advertising": null, "Broadcast Advertising": null } } } }, "Finance": { "Sub-Branches": { "Investment Banking": { "Sub-Branches": { "Equity Research": null, "Mergers & Acquisitions": null } }, "Corporate Finance": { "Sub-Branches": { "Financial Modeling": null, "Risk Management": null } } } } } };
目标树形结构
[{ id: 1677230955479, name: "Marketing", children: [{ id: 1677230955479, name: "Digital Marketing", children: [{ id: 1677230955479, name: "Search Engine Optimization", children: [], }, { id: 1677230955479, name: "Social Media Marketing", children: [], }, ], }, { id: 1677230955479, name: "Traditional Marketing", children: [{ id: 1677230955479, name: "Print Advertising", children: [], }, { id: 1677230955479, name: "Broadcast Advertising", children: [], }, ], }, ], }, { id: 1677230955479, name: "Finance", children: [{ id: 1677230955479, name: "Investment Banking", children: [{ id: 1677230955479, name: "Equity Research", children: [], }, { id: 1677230955479, name: "Mergers & Acquisitions", children: [], }, ], }, { id: 1677230955479, name: "Corporate Finance", children: [{ id: 1677230955479, name: "Financial Modeling", children: [], }, { id: 1677230955479, name: "Risk Management", children: [], }, ], }, ], }, ];
当前实现代码
let data = { "Branches": { "Marketing": { "Sub-Branches": { "Digital Marketing": { "Sub-Branches": { "Search Engine Optimization": null, "Social Media Marketing": null } }, "Traditional Marketing": { "Sub-Branches": { "Print Advertising": null, "Broadcast Advertising": null } } } }, "Finance": { "Sub-Branches": { "Investment Banking": { "Sub-Branches": { "Equity Research": null, "Mergers & Acquisitions": null } }, "Corporate Finance": { "Sub-Branches": { "Financial Modeling": null, "Risk Management": null } } } } } } let result = []; function iterate(obj) { let children = []; if (obj) { for (const [key, value] of Object.entries(obj)) { children.push({ id: Date.now(), name: key, children: value ? iterate(value["Sub-Branches"]) : [] }) } } return children; } // Start From Here for (const [key, value] of Object.entries(data.Branches)) { let obj = {}; obj.id = Date.now(); obj.name = key obj.children = iterate(value["Sub-Branches"]); result.push(obj) } console.log(result)
优化建议
1. 统一递归逻辑,消除重复代码
当前代码中顶层节点处理和子节点处理存在重复的节点创建逻辑,可将顶层流程整合到递归函数中,简化结构:
function convertToTree(obj) { return Object.entries(obj).map(([name, value]) => ({ id: generateUniqueId(), name, children: value?.["Sub-Branches"] ? convertToTree(value["Sub-Branches"]) : [] })); } // 直接调用处理顶层Branches const result = convertToTree(data.Branches);
2. 生成真正唯一的ID
Date.now()会导致多个节点ID相同(代码执行速度远快于毫秒级时间变化),推荐两种实现方式:
方案一:自增计数器
let idCounter = 0; function generateUniqueId() { return ++idCounter; }
方案二:随机混合ID
function generateUniqueId() { return Date.now() + Math.random().toString(36).slice(2); }
3. 简化空值与可选链处理
利用ES6+的可选链(?.)和空值合并运算符(??)简化条件判断,让代码更简洁:
function convertToTree(obj) { if (!obj) return []; return Object.entries(obj).map(([name, value]) => ({ id: generateUniqueId(), name, children: convertToTree(value?.["Sub-Branches"] ?? {}) })); }
4. 封装为可复用函数
将整个转换逻辑封装成独立函数,支持自定义根节点键名,提升灵活性:
function convertHierarchyToTree(data, rootKey = "Branches") { let idCounter = 0; function generateUniqueId() { return ++idCounter; } function traverse(obj) { if (!obj) return []; return Object.entries(obj).map(([name, value]) => ({ id: generateUniqueId(), name, children: traverse(value?.["Sub-Branches"] ?? {}) })); } return traverse(data[rootKey]); } // 调用示例 const result = convertHierarchyToTree(data); // 若根节点键名是"Departments",可传入第二个参数: // const result = convertHierarchyToTree(otherData, "Departments");
5. 处理HTML转义字符
原始数据中的&属于HTML转义字符,若需要还原为普通字符&,可添加转义处理函数:
function unescapeHtml(str) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = str; return tempDiv.textContent || tempDiv.innerText || ''; } // 在节点创建时使用: name: unescapeHtml(name),
内容的提问来源于stack exchange,提问作者Neha Soni
相关产品推荐
相关产品推荐

