这里有很多关于这个问题的帖子,它们都包含很多可以这样概括的断言:
JSON.parse()
从不以任何方式对属性进行排序。显然我们对上面的#1毫无疑问,所以我们可以合理地预期,对于任何操作,属性仅按照它们出现的顺序进行处理。
[编辑,遵循@ Bergi的评论:或者至少它们应该以随机顺序出现]
然后我们可以特别推断#2应该是真的。
但请看这个片段:
(顺便说一句:为了显示结果,下面的片段不要使用console.log()
,这可能会改变输出的顺序。相反,对象会被for (key in obj)
迭代,输出显示在文件)
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 />`);
}
&#13;
它表明,给定一个具有无序键的JSON字符串:
从那时起,我首先想要得出的结论是,实际上会有(未记录的?)功能,因此JSON.parse()
遵循&#34;规则&#34;暴露在上面。
但是我有了进一步观察的想法,所以下面的代码片段显示了仅仅编码对象的属性是如何排序的:
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 />`);
}
&#13;
它产生模拟观察,即无论它们编码的顺序如何,属性都按照上述第3条规则存储:
所以这意味着JSON.parse()
没有参与:实际上它似乎是对象构建的一个基本过程。
这似乎没有记录,至少我能找到。
有关真实,权威的规则的任何线索吗?
[编辑,感谢@Oriol&#39的回答]实际上看起来是合成的:
答案 0 :(得分:3)
对象的属性没有顺序,因此JSON.parse
无法对它们进行排序。但是,当您列出或枚举对象的属性时,顺序可能是明确定义的。
不一定适用于for...in
循环,也不一定适用于Object.keys
正如Does ES6 introduce a well-defined order of enumeration for object properties?中详细解释的那样,spec说
未指定枚举属性的机制和顺序
但对于OrdinaryOwnPropertyKeys
是的对象具有内部[[OwnPropertyKeys]]方法,例如Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
。
对于普通对象,该方法使用OrdinaryGetOwnProperty抽象操作,该操作以明确定义的顺序返回属性:
当调用抽象操作OrdinaryOwnPropertyKeys时 对象 O ,采取以下步骤:
- 让键成为新的空List。
- 对于作为整数索引的 O 的每个属性键 P , 升序数字索引顺序
- 添加 P 作为键的最后一个元素。
- 对于 O 的每个属性键 P ,它是一个String但不是 整数索引,按属性创建的时间顺序递增
- 添加 P 作为键的最后一个元素。
- 对于作为符号的 O 的每个属性键 P ,按属性创建的按时间顺序递增
- 添加 P 作为键的最后一个元素。
- 返回键。
醇>
因此,由于OrdinaryOwnPropertyKeys需要订单,因此实现可能决定按该顺序在内部存储属性,并在枚举时使用它。这就是你所观察到的,但你不能依赖它。
另请注意,非普通对象(例如代理对象)可能有另一个[[OwnPropertyKeys]]内部方法,因此即使使用Object.getOwnPropertyNames
,订单仍可能不同。
答案 1 :(得分:0)
所以我们可以合理地期望,对于任何操作,属性仅按照它们出现的顺序进行处理
推理中存在缺陷的地方。鉴于对象属性不能保证有序,我们必须假设任何操作按其认为合适的任何顺序处理属性。
事实上,引擎的发展方式特别是处理整数属性 - 它们就像数组索引一样,并且以比查找表更有效的格式存储。