一次code review发现的对象排序问题
问题
一次代码review中,发现代码如下:
1 | export const sortByASCII = (obj) => { |
接口传参需要对对象的key按照ASCII码排序后拼接,然后开发写了个对象排序方法,将对象的key排序后,重新插入一个新对象并返回。传参时,调用qs.stringify(sortByASCII(params)),以得到一个ASCII排序后拼接的参数字符串。
这里显然是存在问题的,我们学习js的时候,就有讲过,for in并没有一个统一的遍历标准,在不同浏览器的实现都是不一样的。MDN的for in文档显示:for…in 语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。此外,for in还会遍历原型属性,最好加上hasOwnProperty判断。
解决
最好的办法,显然是我们对对象不进行排序,而是在拼接key的时候再排序。
1 | export const sortObjectEntries = (obj) => { |
这样我们就得到排序后的对象[key, value]数组。
这个方法存在一个问题,就是Object.entries的兼容性,需要写一个polyfill,当Object.entries不存在时,用for in实现一下。
obj排序探究
我用前面的sortByASCII方法试验了几个对象,其实结果还是符合预期的,说明chrome浏览器还是按照插入顺序去遍历的。那么是否所有场景chrome都会这样,是否其他浏览器也这样。查询了一些文档,刚好看到有一篇文章作者对此转了分析。https://juejin.cn/post/6998831933736108039
按照作者的分析,object.keys在现代浏览器排序规则如下:
- 先从小到大遍历正整数部分
- 按接下来会插入顺序遍历剩下的字符串
- 最后再按照插入顺序遍历 Symbol 类型
而for in的情况更复杂,因为最早for in并没有标准,后来采用了跟上面一样的规则。
所以之前的实现方法,当对象的属性都是字符串的时候,在现代浏览器是没有什么问题的。但是如果有正整数字符串的key就会存在问题。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ahao430 的博客!
评论