Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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? 
like image 246
Ben Aston Avatar asked May 06 '15 12:05

Ben Aston


People also ask

Does order of properties in object matter in JavaScript?

YES (but not always insertion order). Most Browsers iterate object properties as: Integer keys in ascending order (and strings like "1" that parse as ints) String keys, in insertion order (ES2015 guarantees this and all browsers comply) Symbol names, in insertion order (ES2015 guarantees this and all browsers comply)

How can you get the list of all properties in an object es6?

To get all own properties of an object in JavaScript, you can use the Object. getOwnPropertyNames() method. This method returns an array containing all the names of the enumerable and non-enumerable own properties found directly on the object passed in as an argument.

Which are the different ways to enumerate all properties of an object?

Using The For-In loop With the For-In Loop we can enumerate all the properties and methods in an object. Let's see a clear example: Example of for-in loop. This is a general approach in enumerating all the properties and methods in an object.

What is the purpose of enumerable attribute when we define a new property in object?

Enumerable attribute The enumerable property attribute defines whether the property is picked by Object.


2 Answers

Note: As of ES2020, even older operations like for-in and Object.keys are 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.


Answer for ES2015-ES2019:

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

For some other operations: Yes, usually.

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

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

When the [[Enumerate]] internal method of O is 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 order of enumerating the properties is not specified but must conform to the rules specified below [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.

And also see this quote from Object.keys:

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

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

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

  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.

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

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

[1] Below it says:

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

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".

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

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

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

like image 51
Oriol Avatar answered Sep 22 '22 08:09

Oriol


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 does define enumeration methods for other methods like Reflect.ownKeys. However, this inconsistency will soon no longer exist, and all property iteration methods will iterate in a predictable manner.

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:

Specifying for-in enumeration order (Stage 4)

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

(1) Numeric array keys

(2) non-Symbol keys, in insertion order

(3) Symbol keys, in insertion order

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

The specification text is rather simple: EnumerateObjectProperties, the problematic abstract method invoked by for..in, etc, whose order used to be unspecified, will now call [[OwnPropertyKeys]], which is the internal method for which iteration order is specified.

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

like image 20
CertainPerformance Avatar answered Sep 21 '22 08:09

CertainPerformance