Object.keys()获取对象的属性是无序的

522 阅读2分钟

面试题:遍历对象的属性为什么是无序的?

场景描述

首先我们看一个正常的例子,按顺序排列。

var obj = {
    '1':'cc',
    '2':'aa',
    '3':'bb',
    '测试':'dd',
    'a':'a'
};
Object.keys(obj); 
结果: ['1', '2', '3', '测试','a']

看起来没什么问题,key的值是按照顺序排列,接下来我们打乱顺序。

var obj = {
    '2':'aa',
    '1':'cc',
    '3':'bb',
    '测试':'dd',
    'a':'a'
};
Object.keys(obj); 
结果: ['1', '2', '3', '测试','a']

输出的结果并没有按照obj可以的书写顺序排序。接下来我们验证猜想是不是按照属性的ASC码升序排序的?

var obj = {
    '2':'aa',
    '1':'cc',
    '3':'bb',
    'a':'a',
    '测试':'dd'
};
Object.keys(obj); 
结果: ['1', '2', '3', 'a', '测试']

由此可见,Object遍历对象并非按照属性的ASC码升序排序的

var obj = {
    '-3':'aa',
    '2':'aa',
    '1.2':'aa',
    '1':'cc',
    '3':'bb',
    'a':'a',
    '测试':'dd'
};
Object.keys(obj); 
结果: ['1', '2', '3', '-3', '1.2', 'a', '测试']

纠正一个普遍的误区:有些回答说将所有属性为数字类型的 key 从小到大排序,其实不然,还必须要符合 「合法的数组索引」 ,也即只有正整数才行,负数或者浮点数,一律当做字符串处理。

查阅文档

ECMA-262(ECMAScript)第三版中描述,for-in 语句的属性遍历的顺序是由对象定义时属性的书写顺序决定的

ECMA-262(ECMAScript)第五版规范中,对 for-in 语句的遍历机制又做了调整,属性遍历的顺序是没有被规定的

Chrome Opera 中使用 for-in 语句遍历对象属性时会遵循一个规律,它们会先提取所有 key 的 parseFloat 值为非负整数的属性, 然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。其它浏览器则完全按照对象定义的顺序遍历属性。

经验总结

阮一峰老师总结的遍历对象的属性遵守的次序规则

  • 首先遍历所有数值键,按照数值升序排列。
  • 其次遍历所有字符串键,按照加入时间升序排列。
  • 最后遍历所有 Symbol 键,按照加入时间升序排列。 敲黑板划重点 只有正整数才行,负数或者浮点数,一律当做字符串处理。并非按照属性的ASC码升序排序

来源声明:用于记录学习心得整理总结,内容非原创。