
在javascript中递归构建层级数据结构时,一个常见的陷阱是由于递归函数的返回值与调用方期望的数据类型不匹配,导致生成的数据结构出现意外的嵌套。原始代码中的 buildtree 函数定义如下:
function buildTree(mainRoot) {
const items = [ // 注意:items 是一个数组
{
label: mainRoot.Name,
name: mainRoot.Name,
expanded: true,
items: [], // 这个数组用于存放子节点
},
];
if (directReportee.has(mainRoot.Id)) {
directReportee.get(mainRoot.Id).forEach((childNodes) => {
// 问题所在:buildTree(childNodes) 返回的是一个数组,而不是单个对象
items[0].items.push(buildTree(childNodes));
});
}
return items; // 返回一个包含单个对象的数组:[{...}]
}其问题在于:
解决这个问题的核心在于确保递归函数 buildTree 的返回值与父节点 items 数组期望的元素类型一致。这意味着 buildTree 函数应该直接返回表示当前节点的 单个对象,而不是一个包含该对象的数组。
修改后的 buildTree 函数将直接构建并返回一个节点对象。当处理子节点时,它会递归调用自身获取子节点对象,然后将这些子节点对象直接推入当前节点的 items 数组中。
以下是经过优化的 buildTree 函数,它解决了上述嵌套问题,并增加了 directReportee 作为参数,以提高函数的封装性和可测试性:
立即学习“Java免费学习笔记(深入)”;
/**
* 递归构建层级JSON树结构
*
* @param {Object} mainRoot - 当前节点的根数据对象,包含 Id, Name 等信息。
* @param {Map<string, Array<Object>>} directReportee - 存储直接下属的映射。
* 键为上级Id,值为直接向其汇报的下属对象数组。
* @returns {Object} 表示当前节点及其所有下属的树结构对象。
*/
function buildTree(mainRoot, directReportee) {
// 构建当前节点对象,注意这里直接创建并返回一个对象
const currentNode = {
label: mainRoot.Name,
name: mainRoot.Id, // 根据期望输出,使用 Id 作为 name 属性
expanded: true,
items: [], // 初始化子节点数组
};
// 检查当前节点是否有直接下属
if (directReportee.has(mainRoot.Id)) {
// 遍历所有直接下属
directReportee.get(mainRoot.Id).forEach((childNode) => {
// 递归构建子节点,并直接将返回的单个子节点对象添加到当前节点的 items 数组中
currentNode.items.push(buildTree(childNode, directReportee));
});
}
// 返回单个节点对象
return currentNode;
}为了更好地演示,我们假设原始输入数据是一个扁平的员工列表,其中包含 Id、Name 和 Reports to Id(上级ID)。
// 假设原始输入数据
const rawData = [
{ Id: '1', Name: 'Lauren Boyle', Email: 'lauren.boyle@example.com', 'Reports to Id': null },
{ Id: '2', Name: 'Banoth Srikanth', Email: 'banoth.srikanth@example.com', 'Reports to Id': '1' },
{ Id: '3', Name: 'Stella Pavlova', Email: 'stella.pavlova@example.com', 'Reports to Id': '2' },
{ Id: '4', Name: 'Srikanth', Email: 'srikanth@example.com', 'Reports to Id': '1' },
{ Id: '5', Name: 'John Doe', Email: 'john.doe@example.com', 'Reports to Id': null }, // 另一个根节点
{ Id: '6', Name: 'Jane Smith', Email: 'jane.smith@example.com', 'Reports to Id': '5' },
];
// 1. 将原始数据转换为 directReportee Map
// 这个 Map 的键是上级Id,值是直接向其汇报的下属对象数组
const directReportee = new Map();
rawData.forEach(item => {
const parentId = item['Reports to Id'];
if (parentId !== null) { // 排除根节点,根节点没有上级
if (!directReportee.has(parentId)) {
directReportee.set(parentId, []);
}
directReportee.get(parentId).push(item);
}
});
// 2. 找到所有根节点
// 根节点是没有 'Reports to Id' 或 'Reports to Id' 为 null 的节点
const rootNodes = rawData.filter(item => item['Reports to Id'] === null);
// 3. 构建最终的树结构
// 如果有多个根节点,则最终结果将是一个包含多个树的数组(树的森林)
const finalTree = rootNodes.map(root => buildTree(root, directReportee));
// 打印生成的JSON树结构
console.log(JSON.stringify(finalTree, null, 2));预期输出格式(示例):
[
{
"label": "Lauren Boyle",
"name": "1",
"expanded": true,
"items": [
{
"label": "Banoth Srikanth",
"name": "2",
"expanded": true,
"items": [
{
"label": "Stella Pavlova",
"name": "3",
"expanded": true,
"items": []
}
]
},
{
"label": "Srikanth",
"name": "4",
"expanded": true,
"items": []
}
]
},
{
"label": "John Doe",
"name": "5",
"expanded": true,
"items": [
{
"label": "Jane Smith",
"name": "6",
"expanded": true,
"items": []
}
]
}
]通过本教程,我们深入探讨了在JavaScript中递归构建JSON树结构时,如何避免因递归函数返回值不匹配而导致的意外数组嵌套问题。核心解决方案在于明确递归函数应返回单个节点对象,并相应调整子节点添加逻辑。遵循这些最佳实践,开发者可以构建出结构清晰、符合预期且易于使用的层级数据结构,从而提升应用程序的数据处理能力。
以上就是JavaScript递归构建JSON树结构:优化节点嵌套问题的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号