I know key order isn\'t guaranteed in JS objects, however, my data structure comes from a backend for which I have no control over. Is there anything I can do to preserve th
No. As you wrote:
I know key order isn't guaranteed in JS objects
If you want the order you need to use an array. If you have an object, then there is no defined order to the properties.
The JSON specification indicates that
An object is an unordered collection of zero or more name/value pairs...
Strictly speaking, the literal JSON text has an order, of course: the text isn't going to suddenly scramble itself. But your desired behavior -- an ordered set of name/value pairs -- is not a construct that JSON provides. You want an object notation to provide semantic meaning beyond the semantics that are required by the JSON specification.
In order words, doing this in JSON
{
"foo": "baz",
"bar": "egg"
}
is description of an unordered set. If you intended for this to describe an ordered set, you're not following the rules of JSON. The data happens to be ordered (because that's how character sequences work), but JSON semantics freely allow an implementation to disregard the order of name/value pairs completely when considering the data present in the input string.
You could write code that operates directly on the JSON input string, to parse the text in such a way that the input order of the keys is remembered somewhere, but a JSON parser implementation is not required to supply that functionality to you.
The correct JSON-idiomatic solution would be to provide an array of key names in the JSON response:
{
data: {
"foo": "baz",
"bar": "egg"
},
order: ["foo", "bar"]
}
Obviously, if you don't control the response, you can't do that. By choosing the represent the data in an object, the author of the response has asserted that order of keys is purely arbitrary. If the author of the JSON intends to assert order of key entries, that assertion is external to the rules of JSON.
As a practical matter, most JavaScript engines will usually choose to report key names in the order their properties were created. However, this behavior is not required by any specification (and is sometimes inconsistent in edge cases), and so could legally differ between engines and versions.
ECMA-262
does not specify enumeration order. The de facto standard is to match insertion order.
No guarantees are given though on the enumeration order for array indices (i.e., a property name that can be parsed as an integer
), because insertion order for array indices would incur significant memory
overhead.
EDIT: added jsfiddle example.
var obj1 = {
a: 'test1',
b: 'test2'
};
var obj2 = {
2: 'test1',
1: 'test2'
};
// max 32bit unsigned is 2,147,483,647
var obj3 = {
2147483649: 'test1',
2147483648: 'test2'
};
// max 64bit unsigned is 9,223,372,036,854,775,807
var obj4 = {
9223372036854770: 'test1',
9223372036854768: 'test2',
};
// != number < 2,147,483,647, order is not changed
console.log(Object.keys(obj1));
// < 2,147,483,647, order is changed
console.log(Object.keys(obj2));
// > 2,147,483,647, order is not changed in Firefox, but changed in Chrome
console.log(Object.keys(obj3));
// > 9,223,372,036,854,775,807, order is not changed in neither Firefox or Chrome
console.log(Object.keys(obj4));
Which means Chrome's javascript
engine V8
will order any 64bit unsigned
numbers, while Firefox's javascript
engine SpiderMonkey
will order any 32bit unsigned
numbers.