1

Originally I had this issue a while back where while the dataset was correct, relying on ordering in javascript as far as an array is concerned wasn't correct, so my solution was something like this, insofar as the json being returned

var json = { //Returned from a database
  data: {
    _0: {key1: val1, key2: val2},
    _1: {key1: val1, key2: val2},
    ...etc etc etc

  }
};

var new_arr = [];
for(var i = 0; i < Object.keys(json.data).length; i++) {
  var obj = json.data["_"+i];
  new_arr.push(obj);
}
console.log(new_arr);

In IE8-11, Firefox, Opera (or any other browser) this behaves as you'd expect. The order is preserved per the keys in the original json object returned.

Chrome, however, puts this out of order abritrarily. The array is not in the expected order. For example, in at least one case, "_36" appears before "_0" in the console.log, then another key is arbitrarily out of order.

Keep in mind the JSON object returns correctly. It's just reordering the data element of the object isn't being pushed into an array correctly. What am I missing?

Note 1: The key/value pairings inside of _0 et al. do not matter. That is not where the issue is. It is with me running a loop, and the array not being in the right order.

Note 2: The loop is correct. It's accessing the properties of json.data in the right order. The problem is that they aren't going into the array in the right order.

Orpheus
  • 727
  • 1
  • 7
  • 22
  • There is currently nothing in the spec that states the order of keys traversed, so it is not "incorrect". Might be changed in the future. – TbWill4321 Nov 17 '15 at 16:14
  • 1
    JSON does not guarantee the order of objects being returned, even when you are pushing them to your array like that. http://stackoverflow.com/a/5525820/4515720 If you are expecting a specific ordering of objects, you will have to do a sort on the array before you use it. – Evan Bechtol Nov 17 '15 at 16:14
  • The kicker here though, is that I'm accessing those properties directly via the loop (`_0`,`_1`,`_2`, etc). The order JSON has them in wouldn't matter and this is a solution to that. It still just is out of order when I try to convert it to an array of objects. Is there a possibility I'm misunderstanding the previous comment? – Orpheus Nov 17 '15 at 16:17
  • When you traverse an **object** (what your `data` is) then the order of keys is not guaranteed since it's not an ordered structure. An array, however, **is** an ordered structure. I know this doesn't help you whatsoever, but that's how things work and there's actually no problem except the fact you are relying on browser providing the order of elements as they appear in the written format. Solution is to either send yourself an actual array or to loop the object and do conversions manually. – Mjh Nov 17 '15 at 16:24
  • But I'm manually accessing json.data's keys in the order `_0`, `_1`, etc. via a loop. I'm not depending on the order in the browser, I'm literally depending on the names assigned to those data sets. I don't care for the order they came in, and the `Object.keys().length` is just to get the length of the dataset for the for loop. Doing it in this manner should mean everything is pushed into the array in the right order. But in chrome, it's not. – Orpheus Nov 17 '15 at 16:32
  • Can you add an example with real data? The code you has posted is useless because all the elements in the array will have the same value ´{key1: val1, key2: val2}´ – Pablo Lozano Nov 17 '15 at 16:49

1 Answers1

3

There is no order between the elements of a javascript object, so if you have something like

var data: {
  _0: 'zero',
  _1: 'one'   
}

There is no "first attribute" and "second attribute", so you cannot expect that the array of keys returned by Object.keys follows any kind of order. The only restriction is that

The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

Extracted from the MDN page (bold are mine).

If an implementation defines a specific order of enumeration for the for-in statement, the same order must be used for the elements of the array returned [by Object.keys]

from the ECMA specs.

If you need to ensure the order, sort the array of keys before looping:

var new_arr = [];
var keys=Object.keys(json.data);
keys.sort(function () {....}); //custom comparator here
for(var i = 0; i < keys.length; i++) {
  var obj = json.data["_"+i];
  new_arr.push(obj);
}
Pablo Lozano
  • 10,122
  • 2
  • 38
  • 59
  • Wouldn't your keys `_0`,`_1` need to be quoted to be legal? – spender Nov 17 '15 at 16:20
  • No, _0 is a valid identifier for an attribute for a variable, '-0' will need to be quoted, for example – Pablo Lozano Nov 17 '15 at 16:22
  • No, they would not need to be quoted – Evan Bechtol Nov 17 '15 at 16:22
  • Oops. My bad. Had my JSON hat on. – spender Nov 17 '15 at 16:22
  • how can you say there's no order, yet also that it's in the same order as for-in? – dandavis Nov 17 '15 at 16:29
  • @dandavis I've updated my answer with the specs from ECMA: any implementation can choose its own order, so there isn't an "official" order. – Pablo Lozano Nov 17 '15 at 16:31
  • Okay, so after some digging. I found an issue elsewhere that was causing the output of it when made into a table to be an issue. Basically, looping through was in fact, completely correct, and `console.log` was tricking me. The looping implementation was completely correct, just someone else changed something that made the end result (outputting to a table) incorrect. tl;dr console.log is lying sometimes. – Orpheus Nov 17 '15 at 16:58
  • I'm not happy with this: my answer was not correct as I did not understand properly your issue and the issue was caused by something out of the scope of your question, so I think we should delete the question and my answer because is misleading and there are other questions explaining the same behavior about attributes and for..in – Pablo Lozano Nov 17 '15 at 17:04
  • @Pablo: ahh, that order makes sense: any but the same. i thought that es2015 codifies V8's ordering (insertion/sorted expandos), but maybe i imagined that... – dandavis Nov 17 '15 at 17:44