Property ordering of [[Enumerate]] / getOwnPropertyNames()

# Jesse McCarthy (5 years ago)

I just want to confirm some things about property enumeration order of plain Objects. I apologize that this has probably already been discussed before, but it's hard to locate a clear answer. Please note that I'm solely asking about ES2015 spec compliance, not what's in the wild.

Given:

var y = Object.create(null);
// Note that property names are all strings.
y.one = 1;
y.two = 2;
y.three = 3;

This is my understanding of what's guaranteed (or not) about enumeration order (in the context of the example given):

  1. No guarantee of order Anything that relies on or has property-order equivalence with [[Enumerate]] or EnumerableOwnNames 1b. for (x in y) 1c. Object.keys(y)

This is based on the statement in 9.1.11 [[Enumerate]] () step 1:

The mechanics and order of enumerating the properties is not specified

Although it says that...

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

...and [[OwnPropertyKeys]] specifies ordering, my reading is that [[Enumerate]] doesn't guarantee that the iterator it returns will preserve the order returned by [[OwnPropertyKeys]].

  1. Guarantee of insertion order (['one', 'two', 'three']) Object.getOwnPropertyNames(y)

Are those interpretations correct?

Related: In this thread... esdiscuss.org/topic/nailing-object-property-order

...Bergi asked these pertinent questions that no one answered:

But why was the default object [[enumerate]] algorithm not specced to match the [[OwnPropertyKeys]] order then? ... Shouldn't we add a guarantee to [[enumerate]] that the subset of enumerated own properties comes in insertion order as well?

This is partly in reference to stackoverflow.com/a/30244410/1034448

# Adam Klein (5 years ago)

This doesn't answer the spec question, exactly, but v8 doesn't currently conform to ES6's requirements for [[OwnPropertyKeys]]: some objects return names in an implementation-dependent order (see code.google.com/p/v8/issues/detail?id=3056 for more details).

# Allen Wirfs-Brock (5 years ago)

On Aug 20, 2015, at 9:54 AM, Jesse McCarthy wrote:

I just want to confirm some things about property enumeration order of plain Objects. I apologize that this has probably already been discussed before, but it's hard to locate a clear answer. Please note that I'm solely asking about ES2015 spec compliance, not what's in the wild.

Given:

var y = Object.create(null);
// Note that property names are all strings.
y.one = 1;
y.two = 2;
y.three = 3;

This is my understanding of what's guaranteed (or not) about enumeration order (in the context of the example given):

  1. No guarantee of order Anything that relies on or has property-order equivalence with [[Enumerate]] or EnumerableOwnNames 1b. for (x in y) 1c. Object.keys(y)

This is based on the statement in 9.1.11 [[Enumerate]] () step 1:

The mechanics and order of enumerating the properties is not specified

Although it says that...

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

...and [[OwnPropertyKeys]] specifies ordering, my reading is that [[Enumerate]] doesn't guarantee that the iterator it returns will preserve the order returned by [[OwnPropertyKeys]].

Correct. Historically, the for-in order was not defined and there has been variation among browser implementations in the order they produce.(and other specifics). ES5 added Object.keys and the requirement that it should order the keys identically to for-in. During development of both ES5 and ES6 the possibility of defining a defining a specific for-in order was considered but not adopted because of web legacy compatibility concerns and uncertainly about the willingness of browsers to make changes in the ordering they currently produce.

If we decided to specify the for-in order it would be the order produced by the informative algorithm provided in 9.1.11.

As a step in that direction, we should consider for ES7 adding to 9.1.11 something like:

If the target object's [[Prototype]] is null, then properties have the same relative ordering for both  [[Enumerate]] and [[OwnPropertyKeys]]
  1. Guarantee of insertion order (['one', 'two', 'three']) Object.getOwnPropertyNames(y)

yes

Are those interpretations correct?

Related: In this thread... esdiscuss.org/topic/nailing-object-property-order

...Bergi asked these pertinent questions that no one answered:

But why was the default object [[enumerate]] algorithm not specced to match the [[OwnPropertyKeys]] order then? ... Shouldn't we add a guarantee to [[enumerate]] that the subset of enumerated own properties comes in insertion order as well?

legacy concerns, see above and numerous historic es-discuss threads

# Jesse McCarthy (5 years ago)

Thanks for the link Adam. Nice to see you're on top of that! (I assume you're the "adamk" there.) That's some coincidental timing.

# Jesse McCarthy (5 years ago)

(duplicate post)

# Jesse McCarthy (5 years ago)

(duplicate post)

# John-David Dalton (5 years ago)

[Enumerate]] must obtain the own property keys of the target object as if

by calling its [[OwnPropertyKeys]] internal method

Whoa that's tricky language. I assumed reading it that [[Enumerable]] was to follow the order of [[OwnPropertyKeys]] (as part of "as if by") and walking the prototype chain.

It's odd to me that:

Reflect.ownKeys() has defined order but Reflect.enumerate() doesn't

I'm using Reflect.enumerate() to create a keysIn implementation (like keys but for own & inherited key names).

:+1: for more defined behavior in ES7.

# Scott Sauyet (5 years ago)

John-David Dalton <john.david.dalton at gmail.com> wrote:

It's odd to me that:

Reflect.ownKeys() has defined order but Reflect.enumerate() doesn't

I'm using Reflect.enumerate() to create a keysIn implementation (like keys but for own & inherited key names).

:+1: for more defined behavior in ES7.

+1

This same concern was tripping me up this week.

# Allen Wirfs-Brock (5 years ago)

On Sep 2, 2015, at 4:10 PM, John-David Dalton wrote:

Hiya,

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

Whoa that's tricky language. I assumed reading it that [[Enumerable]] was to follow the order of [[OwnPropertyKeys]] (as part of "as if by") and walking the prototype chain.

It says "obtain", not "obtain and order". In other words, the initial set of own properties of the target object must include the same set of keys as provided by [[OwnPropertyKeys]] but the order in which they are processed need not be the same. Why? Because TCD39 was not yet willing to mandate a for-in enumeration order.

It's odd to me that:

Reflect.ownKeys() has defined order but Reflect.enumerate() doesn't

Note that [[OwnPropertyKeys]] returns any array whose property ordering is fixed when it is returned. [[Enumerate]] returns an iterator, and the property state of the object that is being iterated over can change between calls to `next1. That's the big difference.

I'm using Reflect.enumerate() to create a keysIn implementation (like keys but for own & inherited key names).

:+1: for more defined behavior in ES7.

me too