Many posts on this topic contain assertions that can be summarized like so:
- Object properties are never guaranteed to be ordered in any way.
JSON.parse()
never sorts properties in any specific way.
We typically have no doubts about #1 above, so it is expected that properties are processed in the order they appear.
[edit, following @Bergi's comment: or at least they should appear in a random order]
From this, we might infer that #2 should also hold true.
However, when looking at the provided snippet:
(Note: To display the results, snippets below do not use console.log()
which may change the output order. Instead, objects are iterated using for (key in obj)
and the output is displayed in the document.)
var inputs = [
'{"c": "C", "a": "A", "b": "B"}',
'{"3": "C", "1": "A", "2": "B"}',
'{"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}'
];
for (var i in inputs) {
var json = inputs[i],
parsed = JSON.parse(json),
output = [];
for (var j in parsed) {
output.push(j + ': ' + parsed[j]);
}
document.write(`JSON: ${json}<br />Parsed: ${output.join(', ')})<hr />`);
}
The snippet reveals that:
- When input keys have non-numeric values, the parsed object retains the original order of properties from the input. This aligns with the assumption made in #2.
- Conversely, when keys have numeric values (as strings), the parsed object has its properties sorted. This goes against the assumption made in #2.
- Additionally, in cases where there are both numeric and non-numeric key values, the numeric properties appear first in sorted order followed by the non-numeric properties in their original order.
Initially, one might conclude that there is an undocumented feature where JSON.parse()
follows the mentioned rules. However, further exploration shows how different objects are handled:
var objects = [
[
'{"c": "C", "a": "A", "b": "B"}',
{"c": "C", "a": "A", "b": "B"}
],
[
'{"3": "C", "1": "A", "2": "B"}',
{"3": "C", "1": "A", "2": "B"}
],
[
'{"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}',
{"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}
]
];
for (var i in objects) {
var object = objects[i],
output = [];
for (var j in object[1]) {
output.push(j + ': ' + object[1][j]);
}
document.write(`Code: ${object[0]}<br />Object: ${output.join(', ')}<hr />`);
}
Similar observations are made where properties seem to follow a specific rule regardless of how they are coded:
- Numerically named properties are all sorted and come first.
- Other properties follow in the order they were coded.
This behavior seems to be inherent to the object building process rather than being attributed to JSON.parse()
. It appears to be a fundamental aspect, albeit undocumented from what I could find.
Any insights into the definitive rules governing property order?
[Edit, thanks to @Oriol's answer] A synthetic explanation is as follows:
- This behavior aligns with an ECMA specification rule.
- While this rule should apply to methods where order is guaranteed, it is optional for other scenarios.
- Modern browsers seem to uniformly apply this rule across all methods, leading to the observed contradictions.