ES6是否为对象属性引入了定义明确的枚举顺序?
var o = {
'1': 1,
'a': 2,
'b': 3
}
Object.keys(o); // ["1", "a", "b"] - is this ordering guaranteed by ES6?
for(let k in o) {
console.log(k);
} // 1 2 3 - is this ordering guaranteed by ES6?
ES6是否为对象属性引入了定义明确的枚举顺序?
var o = {
'1': 1,
'a': 2,
'b': 3
}
Object.keys(o); // ["1", "a", "b"] - is this ordering guaranteed by ES6?
for(let k in o) {
console.log(k);
} // 1 2 3 - is this ordering guaranteed by ES6?
Object.getOwnPropertyNames
,Object.getOwnPropertySymbols
和Reflect.ownKeys
顺序被定义。
Object.keys
和for.. in
loops的迭代顺序,以及规范:19.1.2.16(Object.keys)调用7.3.21(EnumerateOwnProperties),这又保证:“对元素的顺序进行排序属性,因此它们的迭代顺序与Iterator产生的相对顺序相同,如果用O调用EnumerateObjectProperties内部方法,则会返回该迭代器。[[OwnPropertyKeys]]
-EnumerateOwnProperty依次执行保证(9.1.11)和9.1.11.1(ordinaryownpropertykeys)来保证顺序。
Answers:
注意:从ES2020开始,甚至更旧的操作(例如for-in
和)Object.keys
都必须遵循属性顺序。这不会改变以下事实:使用基本程序逻辑的属性顺序可能不是一个好主意,因为非整数索引属性的顺序取决于创建属性的时间。
ES2015-ES2019的答案:
对于for-in
,Object.keys
和JSON.stringify
:第
对于一些其他操作:是的,通常。
虽然ES6 / ES2015增加了财产秩序,它不需要for-in
,Object.keys
或者JSON.stringify
遵循这一顺序,由于传统的兼容性问题。
for-in
根据[[Enumerate]]循环循环,[[定义为(强调我的):
调用O的[[Enumerate]]内部方法时,将执行以下步骤:
返回一个Iterator对象(25.1.1.2),其下一个方法迭代O的所有可枚举属性的String值键。Iterator对象必须继承%IteratorPrototype%(25.1.2)。没有指定枚举属性的机制和顺序,但必须符合下面[1]中指定的规则。
ES7 / ES2016删除了[[Enumerate]]内部方法,而是使用了抽象操作EnumerateObjectProperties,但是就像[[Enumerate]]一样,它没有指定任何顺序。
也可以从查看此报价Object.keys
:
如果实现为for-in语句定义了特定的枚举顺序,则[...]
这意味着不需要实现来定义特定的枚举顺序。ECMAScript 2015语言规范的项目编辑Allen Wirfs-Brock在规范完成后发表的帖子中已确认了这一点。
其他操作,如Object.getOwnPropertyNames
,Object.getOwnPropertySymbols
,Object.defineProperties
,并Reflect.ownKeys
做好后续普通物体下面的命令:
此行为在[[OwnPropertyKeys]]内部方法中定义。但是某些特殊对象对内部方法的定义稍有不同。例如,代理的ownKeys
陷阱可能以任何顺序返回数组:
console.log(Reflect.ownKeys(new Proxy({}, {
ownKeys: () => ['3','1','2']
}))); // ['3','1','2'], the integer indices are not sorted!
[1]下面说:
[[Enumerate]]必须获得目标对象自己的属性键, 就像通过调用其[[OwnPropertyKeys]]内部方法一样。
并且[[OwnPropertyKeys]]的顺序是明确定义的。但是请不要让您感到困惑:“好像”仅表示“相同的属性”,而不是“相同的顺序”。
可以在EnumerableOwnNames中看到,它使用[[OwnPropertyKeys]]获取属性,然后对它们进行排序
如果调用[[Enumerate]]内部方法,则返回的顺序与Iterator产生的顺序相同。
如果要求[[Enumerate]]以与[[OwnPropertyKeys]]相同的顺序进行迭代,则无需重新排序。
Object.getOwnPropertyNames({ 20 : 'a', 10 : 'b' })
的[ "10", "20" ]
数值排序,而不是书面命令。
for-in
或Object.keys
将是一个传统的兼容性问题?
for-in
或Object.keys
不遵循该规范,但当前版本的Firefox,Chrome和Edge都可以:jsfiddle.net/arhbn3k2/1这很有意义,但是有多个枚举实现是很奇怪的。规范并不需要它,因为不同的引擎已经具有与新定义的顺序不同的狂妄行为,并且委员会不想要求实现可能破坏现有代码的实现。不过,这些实现似乎已经决定要这样做。Firefox的顺序肯定是不同的。
Object.keys
遵循这样的新命令。这是不正确的,因为ES2020现在确实需要它,这尤其是因为引擎已经更新(请参阅我从2017年开始的评论)。由于Oriol不再对SO有所贡献,因此我在答案的顶部添加了注释。
作为覆盖对方的回答,ES2015不会为(很常用的)属性来定义枚举顺序迭代方法for-in
,Object.keys
和JSON.stringify
,而它也定义好其他方法,如枚举的方法Reflect.ownKeys
。但是,这种不一致很快将不再存在,并且所有属性迭代方法都将以可预测的方式进行迭代。
正如许多人在使用JS和注释中所观察到的那样,尽管上述方法的规范无法保证属性迭代的顺序,但是每个实现几乎总是以相同的确定性顺序进行迭代。结果,有一个(完成的)提案可以更改规范以使此行为正式生效:
这个建议,在大多数情况下,for..in
,Object.keys
/ values
/ entries
,并JSON.stringify
保证迭代,以便在:
(1)数字数组键
(2)非符号键,按插入顺序
(3)符号键,按插入顺序
与Reflect.ownKeys
保证其他方法迭代的顺序相同。
的规范的文本是相当简单的:EnumerateObjectProperties
通过调用的问题抽象方法for..in
等,其顺序使用是未指定的,现在将调用[[OwnPropertyKeys]]
,这是它的迭代顺序内部方法被指定。
当前有几种不同的实现尚无法达成共识的情况,在这种情况下,结果顺序将继续不确定,但这种情况很少。
此问题与EcmaScript 2015(ES6)有关。但应注意,EcmaScript2017规范删除了以前出现在的规范中的以下段落Object.keys
,此处引用了EcmaScript 2016规范:
如果实现为for-in语句定义了枚举的特定顺序,则必须对步骤3中返回的数组元素使用相同的顺序。
此外,EcmaScript 2020规范从的部分中删除了以下段落,该段落EnumerableOwnPropertyNames
仍然出现在EcmaScript 2019规范中:
- 对属性的元素进行排序,以使它们具有与Iterator产生的相对顺序相同的相对顺序,如果使用O调用EnumerateObjectProperties内部方法,则会返回该迭代器。
这些清除意味着从EcmaScript的2020年起,Object.keys
实施统一的具体顺序Object.getOwnPropertyNames
和Reflect.ownKeys
,即在指定的OrdinaryOwnPropertyKeys。顺序是:
1个一种数组索引是一个字符串值属性密钥是一个规范的数字串2,其数值我是一个整数的范围0≤我<2 32 - 1。
2甲规范数字串是通过将产生一个数字的字符串表示ToString
,或字符串“-0”。因此,例如,“ 012”不是规范的数字字符串,而是“ 12”。
应该注意的是,所有主要的实现都已经在几年前与这个命令保持一致。
Object.assign()
。在后一种情况下,它可能是词法的或来自输入对象,但这是否必须?
Object.assign
(和属性扩展)的行为遵循源对象的属性顺序。所以Object.keys({a:1,b:2})
(现在)可靠,["a","b"]
而且Object.keys({b:2,a:1})
(现在)可靠["b","a"]
。但是一般而言,最好不要依赖对象属性的迭代顺序。依托创建/分配的量级上是细(和共同:const copy = {...original, x: true};
在可靠地产生的结果copy.x
是true
)。:-)