• 欢迎访问web前端中文站,JavaScript,CSS3,HTML5,web前端demo
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏web前端中文站吧

回归基础:JavaScript 中的数据格式转换一例

ES2015(ES6) web前端中文站 2年前 (2017-08-09) 727次浏览 已收录 0个评论

回归基础:JavaScript 中的数据格式转换一例

常见问题

打个比方,你有一组数据,需要根据拼音首字母字母索引显示在页面上,如图:

更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏

回归基础:JavaScript 中的数据格式转换一例

这种索引性的展示已经随处可见。对于我们前端开发来说这种展示最喜欢的数据格式可能是这样的:

var cardList = [ { "key":"p", "cars":[ { "id":"888888888888888888", "name":"帕加尼", "logo":"http://...", "initial":"p"  } ] },     { "key":"q", "cars":[ { "id":"888888888888888889", "name":"起亚", "logo":"http://...", "initial":"q"  }, { "id":"888888888888888890", "name":"奇瑞", "logo":"http://...", "initial":"q"  }, ... ] }, ... ]; 

或者这样:

var cars = { "p":[ { "id":"888888888888888888", "name":"帕加尼", "logo":"http://...", "initial":"p"  } ], "q":[ { "id":"888888888888888889", "name":"起亚", "logo":"http://...", "initial":"q"  },{ "id":"888888888888888890", "name":"奇瑞", "logo":"http://...", "initial":"q"  }, ... ] ... }; 

相信对于大多数的前端来说,这样的数据去格式化模板都是非常受欢迎的。相比之下,对于上面的例子来说,第一种数据格式更加方便前端大多数的模板使用,而第二种方式更加直观。然而,我们后端的同事吐给我们的很可能是这样的数据格式:

var cars = [ { "id":"888888888888888888", "name":"帕加尼", "logo":"http://...", "initial":"p"  },{ "id":"888888888888888889", "name":"起亚", "logo":"http://...", "initial":"q"  }, { "id":"888888888888888890", "name":"奇瑞", "logo":"http://...", "initial":"q"  } ... ]; 

相信大家都多次遇到过类似的问题,除了转换数据格式外我找不到一个真正满意的解决方案。对于前端来说最简单办法可能是叫后端转换成你想要的数据格式。不过这肯定不是这篇文章想要说明的,我们需要自己动手将数据格式转换成我们想要的。根据上面的例子,做直观的做法是将数据按首字母分组,可惜的是 Javascript 的 Array 对象中没有原生的 groupBy() 方法,但我们自己添加一个不是太难。

groupBy()

Javascript 提供了许多其他功能强大的方法,比如 map()filter()sort() 等等。今天我们用一个 ES5 的方法 reduce()

reduce() 方法的工作原理是 将累加器和数组中的每个元素 (从左到右)应用一个函数, 本质上它的目的是将一个数组 “减少” 成一个对象。详细说明可以查看 MDN 文档。下面就用 reduce() 方法来实现 groupBy()

Array.prototype.groupBy = function(prop) { return this.reduce(function(groups, item) { var val = item[prop].toUpperCase(); groups[val] = groups[val] || []; groups[val].push(item); return groups; }, {}); } 

这里来稍微解析一下:

Array.prototype.groupBy = function(prop) { ... } 

首先,我们在 Array 的原型对象上添加一个 groupBy 方法,这意味我们可以在任何 Array 对象上调用这个方法,类似这样:.groupBy(prop) 。其中 prop 参数使我们想要分组的属性名。当然如果你觉得这样做会污染 Array 的原型对象的话,你可以将其改写成工具函数:

function groupBy (arr,prop){ return arr.reduce(function(groups, item) { var val = item[prop].toUpperCase(); groups[val] = groups[val] || []; groups[val].push(item); return groups; }, {}); } 

接下来我们看方法内部实现。

return this.reduce(function(groups, item) { ... }, {}); 

我们在需要处理的数组上调用 reduce() 方法,并传入两个参数,第一个是 callback ,我们要在数组中的每个元素上运行的函数,第二个是累加器,本质上说这个参数是用于第一次调用 callback 函数的第一个参数。因为我们需要得到是一个对象,为此,我们使用一个空对象 {}

reduce()方法将遍历数组中的每个元素,通过传入累加器和当前元素调用我们的 callback 函数。该 callback 函数的工作是找出将元素放在累加器中的位置,然后返回更新的累加器,具体实现:

var val = item[prop].toUpperCase(); groups[val] = groups[val] || []; groups[val].push(item); return groups; 

我们希望根据给定属性的值对所有数组元素进行分组。所以如果该属性是 initial ,那么在开始的例子中,起亚和奇瑞应该在一个分组中,因为他们的首字母都是q

  • 第 1 行:将获取当前数组元素给定属性的属性值,为了展示需要,使用 toUpperCase() 将其转换为大写字母。
  • 第 2 行:是检查我们是否已经为给定属性的属性值设置了一个新的数组,如果累加器中没有该数组,则添加一个空数组。
  • 第 3 行:将当前数组元素添加到刚刚添加的数组中。
  • 第 4 行:返回更新的累加器,传递给下一次遍历,因此下一个遍历的数组元素可以更新到累加器上。

没几行代码,就可以帮我们完整数据格式转换。

示例

回调最开始的例子,我们来验证一下我们的 groupBy() 方法。

Array.prototype.groupBy = function(prop) { return this.reduce(function(groups, item) { var val = item[prop].toUpperCase(); groups[val] = groups[val] || []; groups[val].push(item); return groups; }, {}); } var cars = [ { "id":"888888888888888888", "name":"帕加尼", "logo":"http://...", "initial":"p"  },{ "id":"888888888888888889", "name":"起亚", "logo":"http://...", "initial":"q"  }, { "id":"888888888888888890", "name":"奇瑞", "logo":"http://...", "initial":"q"  } ]; var cardGurop = cars.groupBy("initial"); // cardGurop 的结果是: // { //     "P":[ //             { //                 "id":"888888888888888888", //                 "name":"帕加尼", //                 "logo":"http://...", //                 "initial":"p"  //             } //     ], //     "Q":[ //             { //                 "id":"888888888888888889", //                 "name":"起亚", //                 "logo":"http://...", //                 "initial":"q"  //             },{ //                 "id":"888888888888888890", //                 "name":"奇瑞", //                 "logo":"http://...", //                 "initial":"q"  //             } //     ] // } 

进一步转换数据格式

好了,大功告成?或许这不是我们要的最终结果,实际工作中,以下的数据格式可能更加适用于我们前端模板:

var cardList = [ { "key":"P", "cars":[ { "id":"888888888888888888", "name":"帕加尼", "logo":"http://...", "initial":"p"  } ] },     { "key":"Q", "cars":[ { "id":"888888888888888889", "name":"起亚", "logo":"http://...", "initial":"q"  }, { "id":"888888888888888890", "name":"奇瑞", "logo":"http://...", "initial":"q"  }, ... ] }, ... ]; 

那么我们可能需要进一步装换一下。思路也很简单,将 groupBy() 方法装换出来的 cardGurop 对象再装换一次:

var keyArr = Object.keys(cardGurop); var cardList = []; keyArr.forEach(key => { cardList.push({ "key"  : key, "cars" : cardGurop[key] }) }); // cardList 的结果是: // [ //     { //         "key":"P", //         "cars":[ //             { //                 "id":"888888888888888888", //                 "name":"帕加尼", //                 "logo":"http://...", //                 "initial":"p"  //             } //         ] //     },     //     { //         "key":"Q", //         "cars":[ //             { //                 "id":"888888888888888889", //                 "name":"起亚", //                 "logo":"http://...", //                 "initial":"q"  //             }, //             { //                 "id":"888888888888888890", //                 "name":"奇瑞", //                 "logo":"http://...", //                 "initial":"q"  //             } //         ] //     } // ]; 

总结

实际工作中,掌握一些数据格式装换的技能非常有用,也非常常见,后端同事对于同一份数据可能只会给你一个接口或一种数据格式。除非你碰到了一个大好人,碰到个较真的会跟你谈人生,谁都希望自己代码的逻辑简单。当然我这里只是给了一个最简单的示例,你可能会碰到数据格式装换或者数据操作更加复杂的情况。学习 Javascript 基础和原生对象的方法非常重要。

当然,你也可以使用一些工具类库来解决问题,比如 Lodash 和 Underscore.js 都包含我们上面说的 groupBy 方法,当然还有很多其他有用的方法。不过对于一些有洁癖的工程师来说,一个简单的小功能,引入一个类库,确实有点不值。

 

【注:本文源自网络文章资源,由站长整理发布】


web 前端中文站 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:回归基础:JavaScript 中的数据格式转换一例
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址