loading...

Traversal Order of Object Properties in JavaScript ES6

eladtzemach profile image Elad Tzemach ・3 min read

Have you ever seen code that receives a JSON object response from a backend service then and uses that object to create React components?

Object.keys(data).map((entry) => {
  <MyComponent key={entry.id} name={entry.name} ... />;
});

I have seen it many times 😱, and while it might be ok in some cases, it's very risky! Especially if those <MyComponent />s need to be displayed in the order they were received/inserted in.

ES6 Object Traversal

Before ES6, the order in which object properties were traversed was left unspecified and so each engine handled it as it saw fit 😬

With ES6, the traversal order was guaranteed for some methods:

  • Object.getOwnPropertyNames()
  • Reflect.ownKeys()
  • Object.getOwnPropertySymbols()

But not others:

  • Object.keys()
  • Object.values()
  • Object.entries()
  • JSON.stringify()
  • for .. in loops

As you may have noticed, the most popular methods are the ones that don't guarantee the order 😒

The ones that do guarantee it, follow the [[OwnPropertyKeys]] internal method which specifies the following order:

  • Integer indices (if applicable), in ascending order.
  • Other string keys (if applicable), in property creation order.
  • Symbol keys (if applicable), in property creation order.
const obj = {
  [Symbol('first')]: 'symbol: first'
  '5': 'integer: 5',
  'foo': 'string: foo',
  '01': 'string: 01',
  2: 'integer: 2',
};

console.log(Reflect.ownKeys(obj));
// ["2", "5", "foo", "01", Symbol(first) ]

And what about those other popular methods like Object.keys()?

Although the current versions of some major browsers implement this very same order for those popular methods as well - ES6 implementations are NOT required to define a specific order of enumeration for those popular methods, so you would be better off not counting on it in your code.
(I have personally seen this order not working on Safari 13.1.2 when i used Object.keys() in one of my projects 😟)

What are the alternatives?

Excluding some third-party libraries, if you are looking to guarantee iteration according to insertion order, an Array or a Map would be a safer choice!

Is there any hope?

Well, actually.. there is! 😻

There was a proposal to change the ECMA specification and make this [[OwnPropertyKeys]] order behavior official for all of those popular object traversal methods as well, and that proposal has been accepted and merged into the main specification!

This means that as of ES2020, property order for these popular methods is guaranteed by the ECMA specification to be iterated over in the same deterministic manner as the other ones!

Conclusion

Object traversal order in JavaScript has always been tricky due to different browser implementations, but ES2020 has finally provided a deterministic order standard for all of the popular traversal methods.
Still, this order might not work for you - your project might include objects with a mix of integer and string keys, yet require traversal according to insertion order.

It's good to know how object traversal works, and it's also good to know that there are alternatives you could use 😊

Happy coding! 🚀 🚀 🚀

Discussion

pic
Editor guide