TIL: Property order is predictable in JavaScript objects since ES2015
Tags: javascript
Published: 2018-10-19 10:39:30

---
title: TIL: Property order is predictable in JavaScript objects since ES2015
published: true
tags: javascript
canonical_url: https://www.stefanjudis.com/today-i-learned/property-order-is-predictable-in-javascript-objects-since-es2015/
---

Today's learning surprised me!

I was reading Twitter and came across [a thread started by Sebastian McKenzie](https://twitter.com/sebmck/status/1052268240028676096). In this thread, he shared a React snippet that would rely on the order of specific properties in an object.

```javascript
styles({
  backgroundBlue: true,
  backgroundRed: true
});
```

In the snippet above the background would be red as "it appears last". If you do JavaScript for a while, you might immediately think – __Wait, what__!?!

*In this post, I mainly share snippets and facts because I don't want to repeat the content of resources listed at the end.*

## The common misconception – "the order of JavaScript properties cannot be guaranteed"

When you started writing JavaScript a few years ago, you might have heard the statement that the order of properties in JS objects is not predictable. I never came across an odd and unusual order of properties, but I always followed the rule "never rely on property order".

### The internal `ownPropertyKeys` method

It turns out – since ES2015 there are methods that are based on specific rules defining the order of properties, and apart from one particular case the order is chronological. The order of properties in an object depends on the type of the included properties and their values.

Looking at the spec the rules are defined in [the internal "ownPropertyKeys" method](http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys). Which is used for example by fairly new methods `Object.getOwnPropertyNames` and `Reflect.ownKeys`.

What is interesting is that there was a spec change of e.g. `Object.keys` from [ES5](https://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.14) to [ES6](http://www.ecma-international.org/ecma-262/6.0/#sec-object.keys). The ES6 spec defines that `Object.keys` also relies on `ownPropertyKeys` which makes it predictable in today's browsers, too.

This also means that you have to be careful with this method, though, and shouldn't rely on a predictable order using `Object.keys` because the results [may vary depending on the browser implementation](https://www.reddit.com/r/javascript/comments/9ozyn3/property_order_is_predictable_in_javascript/e7yhm3g/). 

But enough of the theory: let's have a look at the defined property order for methods implementing `ownPropertyKeys`.

#### 1. Integer Indices 

All properties that are integer indices appear first in the overall object property order and are sorted numerically.

```javascript
const objWithIndices = {
  23: 23,
  '1': 1,
  1000: 1000
};

console.log(Reflect.ownKeys(objWithIndices));
// [1, 23, 1000]
// ☝️ following numeric order
```

#### 2. Strings (that are no integers)

Properties that do not count to integer indices and are not of type
`Symbol` come next and follow chronological order.

```javascript
const objWithStrings = {
  'bar': 'bar',
  '01': '01'
};

objWithStrings.last = 'last';
objWithStrings['veryLast'] = 'veryLast';

console.log(Reflect.ownKeys(objWithStrings));
// ['bar', '01', 'last', 'veryLast']
// ☝️ following chronological order
```

#### 3. Symbols

At last, Symbols follow a chronological order, too.

```javascript
const objWithSymbols = {
  [Symbol('first')]: 'first',
  [Symbol('second')]: 'second'
};

objWithSymbols[Symbol('last')] = 'last';

console.log(Reflect.ownKeys(objWithSymbols));
// [Symbol(first), Symbol(second), Symbol(last)]
// ☝️ following chronological order
```

## All together 

When you combine these rules, you’ll see that integers are always in the “front row” of object properties followed by strings and Symbols. __Moreover, we can control the order of the string and Symbol properties because they’re chronological!__

```javascript
const obj = {
  '2': 'integer: 2',
  'foo': 'string: foo',
  '01': 'string: 01',
  1: 'integer: 1',
  [Symbol('first')]: 'symbol: first'
};

obj['0'] = '0';
obj[Symbol('last')] = 'symbol: last';
obj['veryLast'] = 'string: very last';

console.log(Reflect.ownKeys(obj));
// [ "0", "1", "2", "foo", "01", "veryLast", Symbol(first), Symbol(last) ]
// -> 1. integers in numeric order
// -> 2. strings in chronological order
// -> 3. Symbols in chronological order
```

*Edited: As Malgosia Stepniak pointed out "own property order" is [only fully supported in modern browsers and not in e.g. IE](https://twitter.com/malgosiastp/status/1052539495453773824).*

## Additional resources

Thanks to Axel who wrote about this three years ago already. :)

- [The traversal order of object properties in ES6](http://2ality.com/2015/10/property-traversal-order-es6.html#traversing-the-own-keys-of-an-object) by [Axel Rauschmayer](https://twitter.com/rauschma)
- [ECMAScript® 2019 Language Specification - OrdinaryOwnPropertyKeys](https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys)
- ["Does ES6 introduce a well-defined order of enumeration for object properties?"](https://stackoverflow.com/questions/30076219/does-es6-introduce-a-well-defined-order-of-enumeration-for-object-properties) on Stack Overflow