javascript ES6 是否为对象属性引入了明确定义的枚举顺序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30076219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 11:37:52  来源:igfitidea点击:

Does ES6 introduce a well-defined order of enumeration for object properties?

javascriptecmascript-6

提问by Ben Aston

Does ES6 introduce a well-defined order of enumeration for object properties?

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?

回答by Oriol

Note:As of ES2020, even older operations like for-inand Object.keysare required to follow property order. That doesn't change the fact that using property order for fundamental program logic probably isn't a good idea, since the order for non-integer-index properties depends on when the properties were created.

注:由于ES2020的,喜欢更老的操作for-inObject.keys必须遵守财产秩序。这并没有改变这样一个事实,即对基本程序逻辑使用属性顺序可能不是一个好主意,因为非整数索引属性的顺序取决于属性的创建时间。



Answer for ES2015-ES2019:

ES2015-ES2019 的答案:

For for-in, Object.keys, and JSON.stringify: No.

对于for-in, Object.keys, 和JSON.stringify:不。

For some other operations: Yes, usually.

对于其他一些操作:是的,通常。

While ES6 / ES2015 adds property order, it does not require for-in, Object.keys, or JSON.stringifyto follow that order, due to legacy compatibility concerns.

虽然ES6 / ES2015增加了财产秩序,它不需要for-inObject.keys或者JSON.stringify遵循这一顺序,由于传统的兼容性问题。

for-inloops iterate according to [[Enumerate]], which [is defined as (emphasis mine):

for-in循环根据[[Enumerate]]进行迭代,[定义为(强调我的):

When the [[Enumerate]] internal method of Ois called the following steps are taken:

Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of enumerable properties of O. The Iterator object must inherit from %IteratorPrototype% (25.1.2). The mechanics and orderof enumerating the properties is not specifiedbut must conform to the rules specified below [1].

O的 [[Enumerate]] 内部方法被调用时,采取以下步骤:

返回一个 Iterator 对象 ( 25.1.1.2),其 next 方法迭代O的可枚举属性的所有字符串值键。Iterator 对象必须从 %IteratorPrototype% ( 25.1.2)继承。枚举属性的机制和顺序没有指定,但必须符合下面指定的规则[1]

ES7 / ES2016 removes the [[Enumerate]] internal method and instead uses the abstract operation EnumerateObjectProperties, but just like [[Enumerate]] it doesn't specify any order.

ES7 / ES2016 移除了 [[Enumerate]] 内部方法,而是使用抽象操作EnumerateObjectProperties,但就像 [[Enumerate]] 一样,它没有指定任何顺序。

And also see this quote from Object.keys:

还可以看到以下引用Object.keys

If an implementation defines a specific order of enumeration for the for-in statement, [...]

如果实现为 for-in 语句定义了特定的枚举顺序,则 [...]

That means implementations are NOT required to define a specific order of enumeration. This has been confirmedby Allen Wirfs-Brock, Project Editor of the ECMAScript 2015 Language Specification, in a post made after the specification was complete.

这意味着实现不需要定义特定的枚举顺序。ECMAScript 2015 语言规范的项目编辑 Allen Wirfs-Brock 在规范完成后发表的一篇文章中证实了这一点

Other operations, like Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.defineProperties, and Reflect.ownKeysdo follow the following order for ordinary objects:

其他操作,如Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.defineProperties, 和Reflect.ownKeys对普通对象遵循以下顺序:

  1. Integer indices (if applicable), in ascending order.
  2. Other string keys (if applicable), in property creation order.
  3. Symbol keys (if applicable), in property creation order.
  1. 整数索引(如果适用),按升序排列。
  2. 其他字符串键(如果适用),按属性创建顺序排列。
  3. 符号键(如果适用),按属性创建顺序排列。

This behavior is defined in the [[OwnPropertyKeys]]internal method. But certain exotic objectsdefine that internal method slightly differently. For example, a Proxy's ownKeystrap may return an array in any order:

此行为在[[OwnPropertyKeys]]内部方法中定义。但是某些奇异的对象对内部方法的定义略有不同。例如,代理的ownKeys陷阱可能以任何顺序返回一个数组:

console.log(Reflect.ownKeys(new Proxy({}, {
  ownKeys: () => ['3','1','2']
}))); // ['3','1','2'], the integer indices are not sorted!



[1]Below it says:

[1]下面说:

[[Enumerate]] must obtain the own property keys of the target object as ifby calling its [[OwnPropertyKeys]] internal method.

[[Enumerate]] 必须获取目标对象自己的属性键, 就像调用其 [[OwnPropertyKeys]] 内部方法一样。

And the order of [[OwnPropertyKeys]] is well-defined. But don't let that confuse you: that "as if" only means "the same properties", not "the same order".

[[OwnPropertyKeys]] 的顺序是明确定义的。但是不要让这让您感到困惑:“好像”仅表示“相同的属性”,而不是“相同的顺序”。

This can be seen in EnumerableOwnNames, which uses [[OwnPropertyKeys]] to get the properties, and then it orders them

这可以在EnumerableOwnNames中看到,它使用 [[OwnPropertyKeys]] 来获取属性,然后对它们进行排序

in the same relative order as would be produced by the Iterator that would be returned if the [[Enumerate]] internal method was invoked

与 Iterator 生成的相对顺序相同,如果调用 [[Enumerate]] 内部方法,则返回该顺序

If [[Enumerate]] were required to iterate with the same order as [[OwnPropertyKeys]], there wouldn't be any need to reorder.

如果需要 [[Enumerate]] 以与 [[OwnPropertyKeys]] 相同的顺序进行迭代,则不需要重新排序。

回答by CertainPerformance

As covered in the other answer, ES2015 does not define enumeration order for the (very commonly used) property iteration methods for-in, Object.keys, and JSON.stringify, whereas it doesdefine enumeration methods for other methods like Reflect.ownKeys. However, this inconsistency will soon no longer exist, and allproperty iteration methods will iterate in a predictable manner.

作为覆盖对方的回答,ES2015不会为(很常用的)属性来定义枚举顺序迭代方法for-inObject.keysJSON.stringify,而它定义好其他方法,如枚举的方法Reflect.ownKeys但是,这种不一致很快将不复存在,所有属性迭代方法都会以可预测的方式进行迭代。

As many have probably observed in their own experience with JS and in the comments, although property iteration order is not guaranteed by the specification for those methods above, every implementation almost always iterates in the same deterministic order anyway. As a result, there is a (finished) proposal to change the specification to make this behavior official:

正如许多人在他们自己的 JS 经验和评论中所观察到的那样,尽管上述这些方法的规范不保证属性迭代顺序,但无论如何,每个实现几乎总是以相同的确定性顺序进行迭代。因此,有一个(已完成的)提议来更改规范以使此行为正式化:

Specifying for-in enumeration order(Stage 4)

指定 for-in 枚举顺序第 4 阶段

With this proposal, under most circumstances, for..in, Object.keys/ values/ entries, and JSON.stringifyare guaranteed to iterate in order over:

这个建议,在大多数情况下,for..inObject.keys/ values/ entries,并JSON.stringify保证迭代,以便在:

(1) Numeric array keys

(1) 数字数组键

(2) non-Symbol keys, in insertion order

(2) 非符号键,按插入顺序

(3) Symbol keys, in insertion order

(3) 符号键,按插入顺序排列

Which is the same order as with Reflect.ownKeysand the other methods which are already guaranteed to iterate this way.

这与Reflect.ownKeys已经保证以这种方式迭代的其他方法的顺序相同。

The specification textis rather simple: EnumerateObjectProperties, the problematic abstract method invoked by for..in, etc, whose order usedto be unspecified, will nowcall [[OwnPropertyKeys]], which is the internal method for which iteration order isspecified.

规范的文本是相当简单的:EnumerateObjectProperties通过调用的问题抽象方法for..in等,其顺序使用是未指定的,现在将调用[[OwnPropertyKeys]],这是它的迭代顺序内部方法指定。

There are a few weird cases which implementations currently do notagree on, and in such cases, the resulting order will continue be unspecified, but such cases are few and far between.

有一些奇怪的情况目前的实现同意,在这种情况下,结果顺序将继续是未指定的,但这种情况很少见。

回答by trincot

This question is about EcmaScript 2015 (ES6). But it should be noted that the EcmaScript2017 specification has removedthe following paragraph that previously appeared in the specification for Object.keys, here quoted from the EcmaScript 2016 specification:

这个问题是关于 EcmaScript 2015 (ES6)。但需要注意的是,EcmaScript2017 规范删除了之前出现在规范中的以下段落Object.keys,这里引用自EcmaScript 2016 规范

If an implementation defines a specific order of enumeration for the for-in statement, the same order must be used for the elements of the array returned in step 3.

如果实现为 for-in 语句定义了特定的枚举顺序,则必须对步骤 3 中返回的数组元素使用相同的顺序。

Furthermore, the EcmaScript 2020 specification removesthe following paragraph from the section on EnumerableOwnPropertyNames, which still appears in the EcmaScript 2019 specification:

此外,EcmaScript 2020 规范从 部分中删除了以下段落,该部分EnumerableOwnPropertyNames仍然出现在 EcmaScript 2019 规范中

  1. Order the elements of propertiesso they are in the same relative order as would be produced by the Iterator that would be returned if the EnumerateObjectProperties internal method were invoked with O.
  1. 属性元素进行排序,使它们的相对顺序与 Iterator 生成的相对顺序相同,如果使用O调用 EnumerateObjectProperties 内部方法,则返回该顺序。

These removals mean that from EcmaScript 2020 onwards, Object.keysenforces the same specific order as Object.getOwnPropertyNamesand Reflect.ownKeys, namely the one specified in OrdinaryOwnPropertyKeys. The order is:

这些清除意味着从EcmaScript的2020年起,Object.keys实施统一的具体顺序Object.getOwnPropertyNamesReflect.ownKeys,即在指定的OrdinaryOwnPropertyKeys。顺序是:

  1. Own properties that are array indexes,1in ascending numeric index order
  2. Other own String properties, in ascending chronological order of property creation
  3. Own Symbol properties, in ascending chronological order of property creation
  1. 自己的属性是数组索引1在上升的数字顺序索引
  2. 其他自己的 String 属性,按属性创建的时间升序排列
  3. 自己的符号属性,按属性创建的时间升序排列

1An array indexis a String-valued property key that is a canonical numeric String2whose numeric value iis an integer in the range +0 ≤ i< 232- 1.

1个一种数组索引是一个字符串值属性密钥是一个规范的数字串2,其数值是一个整数的范围0≤<2 32- 1。

2A canonical numeric Stringis a String representation of a Number that would be produced by ToString, or the string "-0". So for instance, "012" is nota canonical numeric String, but "12" is.

2规范数字串是通过将产生一个数字的字符串表示ToString,或字符串“-0”。例如,“012”不是规范数字字符串,但“12”是。

It should be noted that all major implementations had already aligned with this order years ago.

应该指出的是,所有主要的实现在几年前就已经与这个顺序保持一致。