
本文介绍如何使用 javascript 将包含 `statname`/`statvalue` 对的嵌套数组(如球员统计数据)扁平化,将其动态转换为外层对象的自有属性,从而实现结构简化与数据可访问性提升。
在实际数据处理中,常遇到类似「统计项以对象数组形式嵌套在主体对象内」的结构——例如每位球员的多项指标(Avg、Total Strokes 等)被封装在 stats 数组中,每个元素形如 { statName: "Avg", statValue: "70.356" }。这种结构虽利于序列化,但不利于直接访问(如 player.Avg),也不符合多数前端渲染或分析库对扁平对象的偏好。理想的输出是将 stats 中每项 statName 作为键、statValue 作为值,提升至外层对象层级。
核心思路是:对原始数组执行 .map(),对每个对象解构出 stats 和其余字段(...rest),再利用 .reduce() 将 stats 数组逐项累积为一个新对象,并通过计算属性名 [statName] 动态赋值。最终用展开运算符 ... 合并 rest 与生成的统计对象。
以下是完整实现代码:
const output = input.map(({ stats, ...rest }) => ({
...rest,
...stats.reduce((acc, { statName, statValue }) => ({
...acc,
[statName]: statValue
}), {})
}));✅ 关键点解析:
- ({ stats, ...rest }):安全解构,分离出 stats 数组与其余所有字段(自动排除 stats);
- stats.reduce(..., {}):以空对象为初始值,遍历每个统计项,将 statName 作为动态键、statValue 作为对应值合并进累加器;
- ...acc 与 ...rest 均依赖浅拷贝,适用于本例中值均为基本类型(字符串、数字)的场景;
- 若 stats 中存在重复 statName,后出现的会覆盖前者(符合 reduce 累积逻辑)。
⚠️ 注意事项:
- 若 stats 可能为 null 或 undefined,建议添加守卫逻辑:stats?.reduce(...) || {};
- 若需保留原始 stats 字段,可跳过解构剔除,改为显式保留:{ ...rest, stats, ...transformedStats };
- 对于超大数据集(数千条以上),reduce 内频繁对象展开可能带来轻微性能开销,此时可改用 for...of 循环 + Object.assign 优化。
该方法简洁、可读性强,无需引入外部库,完美契合现代 JavaScript 开发实践,是处理“键值对数组→扁平对象”映射的经典范式。










