现在的web开发普遍采用前后台分离的模式,数据是二者之间的桥梁。
前台需要某项数据时向后台发送请求,后台根据请求,返回数据库中的数据。但在大多数情况下,这些数据是扁平的,并不能直接拿来渲染页面,必需经过js解决成前台所需的数据结构。比方在最近开发的一个抽奖系统中,需要展现各个奖级的中奖名单,如下图所示:

中奖名单要求展现各奖级的中奖者头像和昵称。为了实现这个功能,就需要特定结构的数据。后台返回的中奖名单winner1的数据格式如下:
winner1: [ { avatar: 'http://******90ibeY9c/0', nickname: '大海', awardLevel: '特等奖', ... // 省略其余字段,下同 }, { avatar: 'http://******90ibeY9c/0', nickname: '爱', awardLevel: '一等奖' }, { avatar: 'http://******90ibeY9c/0', nickname: '奔跑', awardLevel: '一等奖' }, { avatar: 'http://******90ibeY9c/0', nickname: 'js解决', awardLevel: '二等奖' }, { avatar: 'http://******90ibeY9c/0', nickname: '扁平数据', awardLevel: '三等奖' }]我们需要按awardLevel分组,而后把属于某个分组(如一等奖)的中奖者(如“爱”“奔跑”)都加入到该分组的list数组中,才能得到我们需要的数据结构:
winner2: [ { level: '特等奖', list: [ { avatar: 'http://******90ibeY9c/0', nickname: '大海' } ] }, { level: '一等奖', list: [ { avatar: 'http://******90ibeY9c/0', nickname: '爱' }, { avatar: 'http://******90ibeY9c/0', nickname: '奔跑' } ] }, { level: '二等奖', list: [ { avatar: 'http://******90ibeY9c/0', nickname: 'js解决' } ] }, { level: '三等奖', list: [ { avatar: 'http://******90ibeY9c/0', nickname: '扁平数据' } ] }]所以,我们需要一个能将winner1转换成winner2的方法:
let winner2 = this.formatWinner(winner1)formatWinner的具体实现:
formatWinner (data) { if (!data.length) { return [] } // 临时数组,用于存放分组依据:awardLevel let temp = [] // 结果数据 let winner = [] // 遍历扁平数据 for (let i = 0; i < data.length; i++) { if (temp.indexOf(data[i].awardLevel) === -1) { // 假如temp中不存在该awardLevel // 先构造内层数据(list: []) let list = [] list.push({ avatar: data[i].avatar, nickname: data[i].nickname }) // 再构造外层数据{level: '', list: []} winner.push({ level: data[i].awardLevel, list // 等同于 list: list }) // 将该awardLevel放入temp数组里 temp.push(data[i].awardLevel) } else { // 假如temp中存在该awardLevel for (let j = 0; j < winner.length; j++) { // 找出属于哪个分组(奖级) if (winner[j].level === data[i].awardLevel) { // 在目标分组(奖级)中push新的中奖者 winner[j].list.push({ avatar: data[i].avatar, nickname: data[i].nickname }) } } } } return winner}