Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome re-ordering object keys if numerics, is that normal/expected

I noticed that certain code that evaluates some shoe sizes for an e-commerce site and outputs them on screen is messing up the order in Chrome.

JSON given can be:

{   "7": ["9149", "9139", "10455", "17208"],   "7.5": ["9140", "9150", "10456", "17209"],   "8": ["2684", "9141", "10457", "17210"],   "8.5": ["9142", "10444", "10458", "17211"],   "9": ["2685", "9143", "10459", "17212"],   "9.5": ["10443", "9144", "10460", "17213"] } 

...which increments sizes in halves.

Upon conversion into an object and iterating though the keys, the natural order is being respected and they come out as:

7, 7.5, 8, 8.5 etc.

But in Chrome only, keys that 'look' like round numbers ALWAYS come out of the object first, so output of a for... in loop is:

7, 8, 9, 7.5, 8.5, 9.5 ...

Object.keys(sizes); // ["7", "8", "9", "7.5", "8.5", "9.5"] 

Here is the test case: https://jsfiddle.net/wcapc46L/1/

It's only affects whole numbers, seems like Webkit / Blink have an optimisation that prefers Object properties that are numeric, maybe it's to do with Branch Prediction or whatever.

If you prefix the object keys with any character, the order remains unaffected and works as intended - FIFO

I think I recall reading that there are no guarantees on the order of properties of an object but at the same time, this is annoying to the extreme and would cause a considerable amount of effort in fixing it for chrome users alone.

Any ideas? is this likely a bug that will get fixed?

edit additionally, I have now discovered this as an issue on the v8 bug tracker:

https://code.google.com/p/v8/issues/detail?id=164

Looks like Blink don't want to fix this and will remain the only browser that will do it.

update whatever hash table optimisation webkit/blink had, has now made its way into gecko (FF 27.0.1) - https://jsfiddle.net/9Htmq/ results in 7,8,9,7.5,8.5,9.5. applying _ before the keys returns the correct / expected order.

update 2017 People are still upvoting and editing this so - It does NOT appear to affect Map / WeakMap, Set etc (as demonstrated by updated main example)

like image 808
Dimitar Christoff Avatar asked Jul 06 '10 13:07

Dimitar Christoff


People also ask

Is object keys order guaranteed?

keys() method, which lets you use a for...of loop, but the order of the resulting object keys is not guaranteed. The behavior is the same for Object. values() or Object. entries() — the order of the object properties can vary from insertion order.

Does object keys always return same order?

YES (but not always insertion order). Most Browsers iterate object properties as: Integer keys in ascending order (and strings like "1" that parse as ints) String keys, in insertion order (ES2015 guarantees this and all browsers comply)

Why does object keys return string?

keys() returns an array whose elements are strings corresponding to the enumerable properties found directly upon object. The ordering of the properties is the same as that given by looping over the properties of the object manually. You get an array of strings, because Property names are strings by definition.

How do you set a key for an object?

Object keys can be dynamically assigned in ES6 by placing an expression in square brackets. Syntax: var key="your_choice"; var object = {}; object[key] = "your_choice"; console. log(object);


1 Answers

It's the way v8 handles associative arrays. A known issue Issue 164 but it follows the spec so is marked 'working as intended'. There isn't a required order for looping through associative arrays.

A simple workaround is to precede number values with letters e.g: 'size_7':['9149','9139'] etc.

The standard will change in the next ECMAScript spec forcing [chrome] developers to change this.

like image 127
Michael Sparks Avatar answered Oct 02 '22 13:10

Michael Sparks