本文讲解如何将包含可选 roles 数组的人员数据,高效扁平化为每个角色独立成项、缺失角色则仅保留基础字段的标准对象数组,并对比 reduce 与 flatMap 的性能差异。
本文讲解如何将包含可选 `roles` 数组的人员数据,高效扁平化为每个角色独立成项、缺失角色则仅保留基础字段的标准对象数组,并对比 `reduce` 与 `flatmap` 的性能差异。
在处理嵌套结构的用户数据时,一个常见需求是:当某人拥有多个角色(roles 数组),需为每个角色生成一条独立记录;若无角色,则仅输出该人的基本信息。原始数据中 roles 字段可能不存在、为空数组或为有效对象数组,因此需兼顾健壮性与性能。
你最初的实现使用了 map 嵌套逻辑,但未解决“多维数组扁平化”问题——map 对每个含角色的 person 返回一个子数组,最终得到的是混合了数组与对象的不规则结构。正确解法需将所有结果项归并到同一层级的一维数组中。
const cleanRoles = (data) => { return data.reduce((acc, { name, roles }) => { if (Array.isArray(roles) && roles.length > 0) { roles.forEach(({ name: roleName }) => { acc.push({ name, role: roleName }); }); } else { acc.push({ name }); } return acc; }, []);};
此写法:
若 person 对象还包含 id、email 等其他字段,可借助剩余参数(...user)动态透传:
const cleanRoles = (data) => { return data.reduce((acc, { roles, ...user }) => { if (Array.isArray(roles) && roles.length > 0) { roles.forEach(({ name: roleName }) => { acc.push({ ...user, role: roleName }); }); } else { acc.push(user); } return acc; }, []);};
这样即使数据扩展为:
{ id: 1, name: "Alfa", roles: [{ name: "admin" }, { name: "editor" }] }
输出也将自动包含 id 字段:{ id: 1, name: "Alfa", role: "admin" }。
对题设输入:
const data = [ { roles: [{ name: "one" }, { name: "two" }], name: "Alfa" }, { roles: [{ name: "three" }], name: "Bravo" }, { name: "Charlie" }];
调用 cleanRoles(data) 输出:
[ { "name": "Alfa", "role": "one" }, { "name": "Alfa", "role": "two" }, { "name": "Bravo", "role": "three" }, { "name": "Charlie" }]
结构规整、语义明确,可直接用于渲染表格、下拉选项或后续数据聚合。