持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
前言
在写JavaScript处理对象时,我们有时候会取一个Object内的所有key或value,然后用这些key或value来完成我们的业务需求,而Object对象要获取其所有的key或value也不难,Object为我们提供了两个方法,分别是Object.keys(obj)取其所有的key和Object.values(obj)取其所有的value。
出现问题
我想获取一个对象的所有value,我原本想返回的数据应该是: ['three','one','two'],可返回的value数组莫名其妙被自动按升序排序了。
const obj = {99: 'three', 0: 'one', 1: 'two'}
console.log(Object.values(obj)); // ['one','two','three']
而如果key是负数,负数不会被排序,正数仍然会被排序,则返回数组排序又是另一种情况:
const obj = {99: 'three', 0: 'one', 1: 'two', '-2':'four','-100': 'five', '-99': 'six'};
console.log(Object.values(obj)); // [ 'one', 'two', 'three', 'four', 'five', 'six' ]
为什么Object.values方法会帮我们自动把所有key是正数的values按照升序进行排序呢?Object.values()返回的顺序背后的逻辑是什么?
探索
从MDN中文文档中可以看见一句话:
Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
Object.values返回值的顺序hefor...in的顺序相同 现代浏览器使用for in语句遍历对象时会遵循一个规律:首先会取出所有 key 的 parseFloat 值为非负整数的属性, 然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有可枚举属性。
const obj = {99: 'three', 0: 'one', 1: 'two', '-2':'four'};
console.log(Object.values(obj)); //[ 'one', 'two', 'three', 'four' ]
for (const key in obj) {
console.log(key+"-"+obj[key]);
}
/**
* 循环结果
0-one
1-two
99-three
-2-four
*/
总结
for..in没有办法保证遍历的顺序,我们不应该依赖它来进行排序。如果代码中要依赖遍历的顺序,请使用数组或Map数据结构,Map的遍历顺序就是插入顺序。