14.4 ES6 中遍历属性键
在 ECMAScript 5 中,一个属性的键可以是字符串或者 Symbol 。现在有五种工具方法从 obj
对象中获取属性键:
Object.keys(obj) : Array<string>
获取所有可枚举的自有(非继承)属性的字符串键。
Object.getOwnPropertyNames(obj) : Array<string>
获取所有自有属性的字符串键。
Object.getOwnPropertySymbols(obj) : Array<symbol>
获取所有自有属性的 Symbol 键。
Reflect.ownKeys(obj) : Array<string|symbol>
获取所有自有属性的键。
Reflect.enumerate(obj) : Iterator
获取所有可枚举属性的字符串键。
14.4.1 属性键的迭代顺序
所有迭代属性键的方法都是一样的顺序:
- 首先是所有的数组索引,按照数字排序。
- 然后是所有字符串键(非索引),按照创建的顺序。
- 然后是所有 Symbol ,按照创建的顺序。
注意,语言规范把索引定义为字符串键,当转换成无符号整数然后再转换回来,仍然是同样的字符串(同样也必须比232-1小,因此数组是有长度限制的)。这意味着规范把数组索引看作字符串键,甚至普通的对象都可以有数组索引:
> Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
['2', '10', 'b', 'a', Symbol()]
为什么规范要标准化属性键返回的顺序?
Tab Atkins Jr. 的回答:
因为,至少对于对象,所有在使用中的实现返回的顺序大致和当前的规范一样,并且大量的代码无形中就写成了依赖这种顺序的形式,如果用不同的顺序来枚举的话,将会造成破坏。既然浏览器必须要实现这种特定的顺序来变得 web 兼容,那么规范就要做这种顺序要求。
有一些关于从 Map/Set 中打破这种顺序的讨论,但是这样做的话就需要我们指定一种代码无法依赖的顺序;换句话说,我们必须让顺序是随机的,而不是非指定的。这要做更多的努力,并且创建顺序是很合理的(例如,参考 Python 中的 OrderedDict ),因此决定让 Map 和 Set 和 Object 一样。
规范中有两部分和本节有关:
- 关于带有数组感觉的对象那一节提到了什么是数组索引。
- 关于内部方法 [[OwnPropertyKeys]] 的那一节定义了属性返回的顺序。