面试题:遍历对象的属性为什么是无序的?
场景描述
首先我们看一个正常的例子,按顺序排列。
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码升序排序
来源声明:用于记录学习心得整理总结,内容非原创。