从扁平数组构建父子模块关系时遇children未定义类型错误
问题分析与修复
错误原因
你遇到的"children未定义"错误,核心是部分模块的父模块不存在于原始data数组中。比如:
- 模块
profile的父模块8e20f926-2eff-446c-8ad1-23f2a7ae14bf不在data里 - 模块
module management的父模块5470ce5a-341f-4c9f-8f76-a3d696f03c02也不在data里
当代码执行const parent = modulesById[module.parent_module_id]时,这些父模块会返回undefined,后续调用parent.children.push(module)自然会抛出错误。
修复方案
在关联父子关系时,先判断父模块是否存在。如果不存在,可将当前模块作为根节点(根据业务需求调整逻辑)。修复后的代码如下:
const data = [ { module_id: "96ac027b-b5ce-4326-b5db-5f7b8cab44fd", module_name: "profile", module_key: "profile", module_description: "profile", parent_module_id: "8e20f926-2eff-446c-8ad1-23f2a7ae14bf", display_order: "3", route_url: "", component_name: "profile", module_type: "menu", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "a2fc7d41-8fb3-4b7d-852f-342b0bc50be5", module_name: "module management", module_key: "module_management", module_description: "module management", parent_module_id: "5470ce5a-341f-4c9f-8f76-a3d696f03c02", display_order: "2", route_url: "", component_name: "modulemanagement", module_type: "tabs", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "abe12d09-5c61-4764-a7ca-c4ec3c0d543f", module_name: "user registration", module_key: "user registration", module_description: "user_registration", parent_module_id: "5470ce5a-341f-4c9f-8f76-a3d696f03c02", display_order: "1", route_url: "", component_name: "userregistration", module_type: "tabs", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "c524e207-c532-43cd-b949-2637b8472369", module_name: "permission", module_key: "permission", module_description: "permission", parent_module_id: "5470ce5a-341f-4c9f-8f76-a3d696f03c02", display_order: "3", route_url: "", component_name: "permission", module_type: "tabs", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "37c05885-a186-430d-b238-f6c236651085", module_name: "change password", module_key: "change_password", module_description: "change password", parent_module_id: "96ac027b-b5ce-4326-b5db-5f7b8cab44fd", display_order: "3", route_url: "/change-password", component_name: "changepassword", module_type: "menu", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "1d528f94-8322-4005-a2e3-0885ddf4c716", module_name: "expand icon", module_key: "expand_icon", module_description: "expand icon ", parent_module_id: "8e20f926-2eff-446c-8ad1-23f2a7ae14bf", display_order: "1", route_url: "", component_name: "expand", module_type: "component", can_read: true, can_modify: true, can_add: true, can_delete: true, can_access: true }, { module_id: "9542e59e-4b2f-41dd-9619-345eb1c115ef", module_name: "permission group", module_key: "permission_group", module_description: "permission group", parent_module_id: "5470ce5a-341f-4c9f-8f76-a3d696f03c02", display_order: "4", route_url: "", component_name: "permissiongroup", module_type: "tabs", can_read: true, can_modify: true, can_add: true, can_delete: false, can_access: true }, ] function createParentChildArray(data) { const modulesById = {}; data.forEach((module) => { if (module.module_id in modulesById) { modulesById[module.module_id].can_read = modulesById[module.module_id].can_read || module.can_read; modulesById[module.module_id].can_modify = modulesById[module.module_id].can_modify || module.can_modify; modulesById[module.module_id].can_add = modulesById[module.module_id].can_add || module.can_add; modulesById[module.module_id].can_delete = modulesById[module.module_id].can_delete || module.can_delete; modulesById[module.module_id].can_access = modulesById[module.module_id].can_access || module.can_access; } else { modulesById[module.module_id] = { ...module, children: [], }; } }); const roots = []; Object.values(modulesById).forEach((module) => { if (module.parent_module_id) { const parent = modulesById[module.parent_module_id]; // 新增:判断父模块是否存在 if (parent) { parent.children.push(module); } else { // 父模块不存在时,将当前模块作为根节点 roots.push(module); } } else { roots.push(module); } }); return roots; }
实现的正确性与效率
正确性
你的核心逻辑没问题:
- 先遍历构建
module_id到模块的映射,同时合并重复模块的权限 - 再遍历映射,将模块挂载到对应父模块下,无父模块的作为根节点
唯一的漏洞是缺少父模块不存在的边界处理,修复后即可正常运行。
效率
这个实现的时间复杂度是O(n)(n为模块数量):
- 第一次遍历:O(n),构建映射
- 第二次遍历:O(n),关联父子关系
空间复杂度是O(n),用于存储映射和结果数组。这是树形结构构建的最优复杂度之一,属于高效实现。
内容的提问来源于stack exchange,提问作者user20202116
相关产品推荐
相关产品推荐

