This proposal has been accepted and merged into the main specification. This repository exists only for historical interest.
Specifying for-in enumeration order
ECMA-262 leaves the order of
for (a in b) ... almost totally unspecified, but real engines tend to be consistent in at least some cases. Furthermore, over the years implementations have observed that anyone who wants to run code on the web needs to follow some constraints not captured by the spec.
This is a stage 4 (finished) proposal to begin fixing that.
Historical efforts to get consensus on a complete specification of the order of for-in have repeatedly failed, in part because all engines have their own idiosyncratic implementations which are the result of a great deal of work and which they don't really want to revisit.
See the exploration directory for background and test cases from before this was a concrete proposal.
A conservative underapproximation of interop semantics
From this list of interop semantics we can derive a conservative underapproximation of cases where engines already agree, which I believe covers the most common common cases. Specifically:
- Neither the object being iterated nor anything in its prototype chain is a proxy, typed array, module namespace object, or host exotic object.
- Neither the object nor anything in its prototype chain has its prototype change during iteration.
- Neither the object nor anything in its prototype chain has a property deleted during iteration.
- Nothing in the object's prototype chain has a property added during iteration.
- No property of the object or anything in its prototype chain has its enumerability change during iteration.
- No non-enumerable property shadows an enumerable one.
There are a variety of APIs which make a property enumeration order observable.
for-in is the most complex, because it, uniquely, enumerates properties from the prototype chain as well. The remaining can be split into those which use the same order as
for-in does for own properties, which are affected by this proposal, and those which use the same order as
Reflect.ownKeys, which are not.
The following APIs use
EnumerableOwnPropertyNames, which requires that its results be ordered "in the same relative order as would be produced by the Iterator that would be returned if the EnumerateObjectProperties internal method were invoked with [the object in question]".
EnumerateObjectProperties is the spec-internal method which is used by
for-in, and is the part of the spec which this proposal is concerned with improving.
The other-effects directory contains tests demonstrating simple examples of how each of these are observable. All major engines already agree in all of these cases.
Because all of the objects produced by
JSON.parse are within the interop semantics, it will be fully specified after this proposal. The others can all be passed exotic arguments and so will not.
The following APIs invoke the
[[OwnPropertyKeys]] internal method directly, whose behavior is fully specified. They are therefore not affected by this proposal.
- object spread (via
- object rest in both assignment and binding position (via
See candidate spec text. This does not yet capture the "no non-enumerable property shadows an enumerable one" constraint above, because I am having trouble figuring out how to say that.