views:

81

answers:

5

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

the JOSN string 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.

through mootools (or any framework, i don't think that's relevant) the JSON is converted into an object which I can then loop through.

the trouble is that in any browser bar chrome, the natural order of the object keys is being preserved, hence I can output them 1 by 1 and get size: 7, 7.5, 8, 8.5 etc.

but in chrome, round integers ALWAYS come on top of the obejct so output is: 7, 8, 9, 7.5, 8.5, 9.5 instead.

here is the test case: http://jsfiddle.net/jruKk/6/

it's not about floats either as demonstrated by the replacement of the . with _ - it is treating them as strings.

if you prefix the JSON keys with a letter so they become strings, the order remains unaffected and as intended.

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?

p.s. in the example (if you are not familiar with mootools) i use Hash which is just a way of extending object so methods can be applied to them (such as .each) but a simple for key in object does the same.

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

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

also mentioned here: http://stackoverflow.com/questions/280713/elements-order-for-in-loop-in-javascript

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

+1  A: 

It would appear that Chrome is treating the integer string as if it were a numeric type when used as an index/property name.

I think relying on the Javascript implementation to preserve the order of what, in some cases, is object properties, and in other cases (certainly with chrome) array indices, is demonstrably an unsafe approach and order of enumeration is probably not defined in the spec. I would suggest adding an additional property to the JSON that indicates a sort order:

{
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
    //etc
}
spender
that can work - i can apply a filter that checks sortOrder property upon looping and injects the elements accordingly in the DOM.
Dimitar Christoff
A: 

I don't think you can call this a bug. Like you say yourself, there is no garantee on how the properties of an object are sorted.

Ridcully
A: 

They're being treated as strings because they are strings. My best suggestion would be to use the same "precision" in all your keys.

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

So, "8.0" instead of "8", etc.

Even then, there are no guarantees, but it is more likely that they'll come out in the same order.

For a better guarantee, perform a sort based on the keys, putting the values into an array in the sorted order.

Ryan Kinal
regretfully, even though this will work for the test case, this won't be an option for the implementation. sizes are a multitude of various options, such as `S,M,L,XL,XXL' or '44,44.5,44.5' or 'One Size' and so forth, as defined on a per-product basis by the merchant. there is tremendous logic involved in sorting the output from MYSQL so it arrives in the correct order and not as strings - it covers something like 40 separate sizes pre-defined in order of preference.
Dimitar Christoff
+1  A: 

When iterating over the properties of an object, the order is specified in the ECMAScript specification as being undefined and any order you may have observed in some environment should not be relied upon. If you need order, use an Array.

Tim Down
+4  A: 

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.

sparksm
change in favour of chrome's current implementation or in favour of preserving the order of definition?
Dimitar Christoff
preserving the order since all other browsers already do this.
sparksm
awesome news! thanks a lot.
Dimitar Christoff
*"The standard will change in the next ECMAScript spec forcing developers to change this."* Really? Where's the evidence for this? The recent ECMAScript 5 spec doesn't specify an order. Sounds like it got dropped at the last minute; who's to say that won't happen again next time?
Tim Down
+1 for the link.
Tim Down
perhaps implied for harmony and not ECMA 5
Dimitar Christoff
It might not be part of the spec. I read about it in John Resig's blog . http://ejohn.org/blog/javascript-in-chrome/
sparksm
hrm he does state `All modern implementations of ECMAScript iterate through object properties in the order in which they were defined. Because of this the Chrome team has deemed this to be a bug and will be fixing it.` - i read that as a positive sign the--again it got posted in 2008 and it's still not the case.
Dimitar Christoff
Well, silly Mr Resig, if he relied on this. Relying on non-uniformly observed rather than specified behaviour is a recipe for bad, unreliable code.
Tim Down