(Partially.)
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 2 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.
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.
All but the last are fairly easy to specify in prose; the last is somewhat harder. As far as I know JavaScriptCore is the only engine which will output anything in this case, because of this longstanding bug, so I am hopeful that point can be discarded.
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.