JS/TS如何将含数组属性的对象转换为指定结构的扁平化数组
问题说明
开发中需要将键为id、值为对应消息数组的对象,转换为每条消息携带对应id的扁平数组,期望输出结果如下:
result = [ { id: 'test-1', message: 'test#1.1' }, { id: 'test-1', message: 'test#1.2' }, { id: 'test-2', message: 'test#2.1' }, { id: 'test-2', message: 'test#2.2' } ]
初始尝试使用Object.keys()搭配map()实现,代码运行结果不符合预期,初始代码如下:
mockData = { 'test-1': [ { message: 'test#1.1' }, { message: 'test#1.2' } ], 'test-2': [ { message: 'test#2.1' }, { message: 'test#2.2' } ] } const result = Object.keys(this.mockData).map((id) => { return { id, ...this.mockData[id], } }) console.log(result)
错误原因分析
- 你判断的方向完全正确:当前写法的核心问题是没有对
this.mockData[id]对应的消息数组做二次遍历。 - 直接展开数组到对象中时,JS会把数组的数字索引作为对象的键,最终生成的结构是
{id: 'test-1', 0: {message: 'test#1.1'}, 1: {message: 'test#1.2'}},外层map返回的是长度为2的数组,和你需要的长度为4的扁平数组结构完全不匹配。
可行实现方案
没有绝对的最佳实现,你可以根据团队代码规范选择以下任意一种写法:
方案1:flatMap 链式实现
最简洁的链式写法,flatMap会自动将内层遍历返回的数组做一层拍平,不需要额外调用flat:
const result = Object.keys(mockData).flatMap(id => mockData[id].map(msgItem => ({id, ...msgItem})) )
方案2:reduce 实现
不需要做数组拍平,遍历过程中直接把组装好的对象推入结果数组,性能和可读性都很好:
const result = Object.entries(mockData).reduce((res, [id, msgList]) => { msgList.forEach(msg => res.push({id, ...msg})) return res }, [])
两种写法运行后都会得到你期望的结果结构。
内容的提问来源于stack exchange,提问作者Aury
相关产品推荐
相关产品推荐

