问题
在实际开发中我们经常会遇到对象{}
添加键值后,迭代出来的key顺序不是我们添加的顺序。就比如:
const obj = {2: 2}
obj[1] = 1
for(const key in obj) {
console.log(key)
}
// 1
// 2
此时1
会跑2
前面去,这其中原因请看下文解析。
解析
在ES6(ES2015)
之前对象的属性迭代顺序规则我没去具体了解,但是自从ES6
之后,对象的属性迭代顺序遵循一组特定的规则,但它始终不遵循插入的顺序。
从ES6
起的规则是:
- 非负整数或类非负整数的
key
按升序排列(例如:非负整数11
、类非负整数‘11’
) - 字符串
key
按插入顺序排列 - 以
Symbol
为key
按插入顺序排列
然后整个对象属性又按这三个规则分段依次排序。
下面直接上示例来直观的体现这套规则:
const obj = {
'm': { value: function() {} },
'2': { value: '2' },
'b': { value: 'b' },
0: { value: 0 },
[Symbol()]: { value: 'syb' },
'1': { value: '1' },
'a': { value: 'a' },
[Symbol(22)]: { value: 'syb22' },
[Symbol('11')]: { value: 'syb11' },
}
现在我们用Reflect.ownKeys(obj)
拿到对象obj
属性的顺序数组,注意,不可以在浏览器中直接console.log(obj)
后来看obj
的属性顺序,此时看到的顺序不是真正迭代时的顺序。
这个顺序结果:
console.log(Reflect.ownKeys(obj)
/*
['0', '1', '2', 'm', 'b', 'a', Symbol(), Symbol(22), Symbol(11)]
*/
从结果中我们可以看到非负整数在前面按规则1排序,字符串在中间按规则2排序,最后是Symbol
类型按规则3排序,符合上面所说的规则。
如何保证顺序呢?
直接用ES6
的新数据结构Map
,可以完美保证你添加的顺序。