The Order of Javascript Object Keys
Tags: javascript, jstrivia
Published: 2020-09-02 17:33:46

Trivia time! What does the following array look like?

```js
Object.keys({
  2: true, 
  1: true,
  '00': true,
  'b': true,
  'a': true,
  '3': true,
})
```

{% details Answer (click to see) %}
```js
[ "1", "2", "3", "00", "b", "a" ]
```
{% enddetails %}

So what exactly is going on?? Here are the ordering rules:

1. Numbers are ordered first, and they are ordered within themselves from smallest to largest as long as they are `>=0` (see below for more details) 
2. Strings come second, and they are ordered within themselves by _insertion_ order
3. Symbols come last, and they are ordered within themselves by _insertion_ order (note that we didn't use symbols in this example)

But wait, why did `'3'` come before `'00'` if strings are ordered within themselves by insertion order?

Well, turns out that JS will see if your string can be converted to a number - if it can, then it will order it with the **numbers** and not the strings. 

And what about `'00'`? Apparently it converts it to a _new number_, then does something similar to `toString()` on _new number_, and compares that _new string_ with the _original string_. 

If they match, then it can be lumped in with the numbers. If it doesn't match, then it's a string.

```js
const originalString = '00'
const stringToNumber = Number(originalString)
const matchesOriginalString = stringToNumber.toString() === originalString // false: '0' !== '00'
```

Pretty clear, huh? :P

Thanks to this article for helping https://www.stefanjudis.com/today-i-learned/property-order-is-predictable-in-javascript-objects-since-es2015/

----

Here's the wording from [the spec](https://tc39.es/ecma262/#sec-ordinaryownpropertykeys):

## Numbers
>For each own property key P of O such that P is an array index, in ascending numeric index order, Add P as the last element of keys.

i.e. insert numerical keys first in ascending order

## Strings

>For each own property key P of O such that Type(P) is String and P is not an array index, in ascending chronological order of property creation, Add P as the last element of keys.

i.e. insert string keys in order of creation as long as they're not an `array index`. So what's that?


>An _integer index_ is a String-valued property key that is a canonical numeric String (see 7.1.21) and whose numeric value is either +0 or a positive integer ≤ 2<sup>53</sup> - 1. An `array index` is an _integer index_ whose numeric value i is in the range +0 ≤ i < 2<sup>32</sup> - 1.

[source for array index](https://tc39.es/ecma262/#array-index)

i.e. a string key that is a canonical numeric string and greater than +0

so... what's a canonical numeric string?

> [A canonical numeric string is an] _argument_ converted to a Number value if it is a String representation of a Number that would be produced by ToString, or the string "-0".

[source for canonical numeric string](https://tc39.es/ecma262/#sec-canonicalnumericindexstring)
i.e. if that string is the same as any number that is `toString()`

## Symbols

>For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, Add P as the last element of keys.

i.e. insert symbol keys in order of creation