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

从扁平数组构建父子模块关系时遇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;
}

实现的正确性与效率

正确性

你的核心逻辑没问题:

  1. 先遍历构建module_id到模块的映射,同时合并重复模块的权限
  2. 再遍历映射,将模块挂载到对应父模块下,无父模块的作为根节点

唯一的漏洞是缺少父模块不存在的边界处理,修复后即可正常运行。

效率

这个实现的时间复杂度是O(n)(n为模块数量):

  • 第一次遍历:O(n),构建映射
  • 第二次遍历:O(n),关联父子关系

空间复杂度是O(n),用于存储映射和结果数组。这是树形结构构建的最优复杂度之一,属于高效实现。

内容的提问来源于stack exchange,提问作者user20202116

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:07:19