3

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.

Malama
  • 135
  • 6
  • 3
    Yes, the order is specified as stated. And what does that syntax error have to do with your question? `{ "3a": ... }` ... – Jonas Wilms Oct 20 '19 at 19:55
  • Jonas Wilms: 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). – Malama Oct 20 '19 at 22:10
  • It's still unclear whether your question is about syntax of object literals or about order of properties. Or is the question really "*Which property names are considered integers in the ordering of keys?*"? – Bergi Oct 20 '19 at 22:14
  • Bergi: The question is writen in the topic header. The rest is information. Ordering is the issue. – Malama Oct 20 '19 at 22:24
  • In that case, it seems to be a duplicate of our canonical question on the topic, where you can find quotes and links to the standard. – Bergi Oct 20 '19 at 22:36
  • It's not a duplicate. See the marked answer in this question. Please realized it. – Malama Oct 21 '19 at 11:50

2 Answers2

1

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.

Domenic
  • 100,627
  • 39
  • 205
  • 257
  • 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). – Malama Oct 20 '19 at 22:06
  • Many thanks Domenic. I think the right answer is in 9.1.11.1 OrdinaryOwnPropertyKeys point 3.: "is a String but is not an array index". The problem is, that keys in object are always integer as the iterator is possible to enumerable. String or not string does not matter. The question about this is, why only integer? [a-zA-Z] also enumerable (characters Unicode number or bits), but not in JS? Objects handle all keys with a integer as a interger, including strings. Thats another problem: `var object = {1:"a","1":"b"}; Object.keys(object); // ["1"]` – Malama Oct 21 '19 at 11:35
  • "including strings": including integer in strings. PS: `array.sort()` sorted also (really) strings with letters. – Malama Oct 21 '19 at 11:55
  • I don't think this answer is correct. The order that `Object.keys` generates is not defined by EnumerateObjectProperties, but by EnumerableOwnPropertyNames, so since ES2017 the order of `Object.keys` is just as well specified as `Reflect.ownKeys`. – trincot Feb 07 '20 at 21:09
-1

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 ,...}.

  • 2
    Actually `var obj1 = {3: 1, 2: 3, 1: 2};` works just fine as well. It's only when you mix digits with letters. – Bergi Oct 20 '19 at 20:26
  • That's a good idea with quote the keys if are integers, but it will handle as integer everywhere, not as a string. I have expand my question above. – Malama Oct 20 '19 at 21:37
  • 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). – Malama Oct 20 '19 at 22:06