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.. inloops的迭代顺序,以及规范: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)。:-)