本文介绍如何将包含可选 roles 数组的人员数据,高效地转换为每个角色(或无角色者)对应一个独立对象的扁平化数组,并提供性能最优的 reduce 实现方案。
本文介绍如何将包含可选 `roles` 数组的人员数据,高效地转换为每个角色(或无角色者)对应一个独立对象的扁平化数组,并提供性能最优的 `reduce` 实现方案。
在处理嵌套结构的数据时,常见的需求是将“一对多”关系(如一人多个角色)展开为多个独立条目。原始数据中,每个 person 对象可能含有 roles 数组(也可能缺失或为空),目标是:
你最初的 map 实现返回了嵌套结构(如 [ [obj, obj], [obj], obj ]),这是因为 map 保持原数组长度和层级,无法自动展平。解决该问题的关键在于使用 reduce 手动累积结果,或选用 flatMap(语义清晰但性能略低)。
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; }, []);};
此写法逻辑清晰、兼容性好(支持所有现代浏览器及 Node.js),且经百万级数据基准测试验证,性能约为 flatMap 方案的 11.7 倍(见原文 benchmark 对比)。
若 person 对象还包含 id、email 等其他字段,需一并透传,可使用对象解构与展开运算符:
const cleanRoles = (data) => { return data.reduce((acc, { roles, ...rest }) => { if (Array.isArray(roles) && roles.length > 0) { roles.forEach(({ name: roleName }) => { acc.push({ ...rest, role: roleName }); }); } else { acc.push(rest); } return acc; }, []);};
例如输入含 id: 123,输出将自动包含 id 字段,无需硬编码。
对示例数据调用 cleanRoles(data),输出严格符合预期:
[ { name: "Alfa", role: "one" }, { name: "Alfa", role: "two" }, { name: "Bravo", role: "three" }, { name: "Charlie" }]
该方案兼顾可读性、健壮性与极致性能,是处理动态嵌套数组展开任务的生产就绪实践。