Object.keys() ordering standard?

Viewed 386

What is the official ordering standard of Object.keys()?
This is not a question over the ordering. It is a question over standard.

Kaushal Regmi wrote:

First, the keys that are integer indices in ascending numeric order. Then, all other string keys, in the order in which they were added to the object. Lastly, all symbol keys, in the order in which they were added to the object. https://stackoverflow.com/a/57929312/10617101

So far so good. Have a Object only integers as keys, there will be saved in ascending numeric order in the Object.keys() returned array. Are the keys only letters, the Object.keys() returned array have the same ordering as in the the called object{}. My question is: Is this a general and global standard in JavaScript? The question about this is: Is it safety?

Next, there is a little problem with that. (i do not use it).

var object = { 3a: 'z', 1a: 'x', 2a: 'y' };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// Firefox: SyntaxError: identifier starts immediately after numeric literal
// Chrome: Uncaught SyntaxError: Invalid or unexpected token
var object = { a3: 'z', a1: 'x', a2: 'y' };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// works on both: [a3, a1, a2]

Yes, the solution is, use another method to create the object{}:

var object = {};
object["3a"] = 'z';
object["1a"] = 'x';
object["2a"] = 'y';
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// [3a, 1a, 2a]

EDIT: The special problem are object keys as integers in quotes:

var object = { "3": "z", "1": "x", "2": "y" };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
} // [1, 2, 3]

Normaly "1" is a string and 1 is a integer, but as object key "1" is still a integer. (but not realy by math with object keys).
Also by the way therefore my question, what is the official standard in the order. And how safety is this.

2 Answers

The spec for Object.keys() is largely a wrapper around the spec-internal operation EnumerableOwnPropertyNames. This, in turn, states

Order the elements of properties so 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.

EnumerateObjectProperties then says

The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below.

and from the "below", the following pieces are relevant to your question:

  • Returned property keys do not include keys that are Symbols.
  • A property name will be returned [...] at most once in any enumeration.

So, per spec, there are no real ordering guarantees at all for Object.keys(). Just some very basic invariants.

The same applies for other parts of the language that bottom out in EnumerateObjectProperties, notably for-in.


Contrast this with Reflect.ownKeys(), which, at least for ordinary objects, bottoms out in OrdinaryOwnPropertyKeys. There, the order is

  • each own property key P of O that is an array index, in ascending numeric index order, do
  • each own property key P of O that is a String but is not an array index, in ascending chronological order of property creation
  • each own property key P of O that is a Symbol, in ascending chronological order of property creation

i.e. for that method, there is a well-specified order. (The same applies to other methods that bottom out in OrdinaryOwnPropertyKeys, such as Object.getOwnPropertyDescriptors().


There is a currently active proposal that attempts to specify stronger restrictions on EnumerateObjectProperties order, and thus on for-in. Its approach is to find scenarios involving a restricted prototype chain and enumeration, where nothing weird is going on, and picking the same order as Reflect.ownKeys() does, for each level in the prototype chain. My reading of the proposal is that, specifically applied to Object.keys(), it would make it behave the same as Reflect.ownKeys() on ordinary objects. I've opened an issue on the proposal to see if I'm correct, and if so to make that more explicit.

If the object key has only numbers javascript will order in ascending order, if don't in the order they were added.

var obj1 = {'3': 1, '2': 3, '1': 2};
var obj2 = {'3a': 1, '2a': 3, '1a': 2};

console.log(JSON.stringify(obj1));
Object.keys(obj1).forEach(function(key) { console.log(key); });

console.log(JSON.stringify(obj2));
Object.keys(obj2).forEach(function(key) { console.log(key); });

If you want to define keys with numbers in the begining followed by letters you must wrap with quotes. Ex.: { '3a': 3 ,...}.

Related