对于Microsoft IE,如果插入带有已删除键的元素且total元素大于31,则JSON对象的顺序将被反转。
到目前为止,此问题仅发生在IE中。 并且,它不会在Chrome,Firefox,Safari和Opera中发生, 该元素会作为插入顺序插入。
可以通过在不同浏览器上运行以下测试代码来重现此问题,并使用不同的" count"值。
<script>
var temp = {};
var count = 31;
add = function(){
for(var i=0; i<count;i++)
{
var id = "id:"+i;
var c = {};
c[id] = "value:"+i;
console.log("push at " + i + " = " + id);
_.extend(temp, c);
}
}
display = function(){
var i=0;
$.each(temp,function(key, value){
console.log("list at "+i+" = " + key);
i++;
});
}
deletion = function(){
var i=0;
$.each(temp,function(key, value){
console.log("delete at " + i+ " = "+key);
delete temp[key];
i++;
});
}
add();
display();
deletion();
add();
display();
</script>
请注意,根据ECMA标准将元素推送到JSON对象时,排序并不重要。
答案 0 :(得分:2)
首先,这不是一个JSON对象,它是一个JS对象。 JSON是一种序列化格式,用于传递包含编码数据的文本字符串; JS中的对象是一个实际的对象,而不是一个对象的字符串表示。
其次,JS对象(以及发生的JSON对象)被明确定义为无序的键值对。您可以迭代它们,但不能依赖于以任何特定顺序获取元素。
JS的简单实现只是将每个新的键值对添加到列表的末尾。但这意味着无论何时访问特定密钥,都必须搜索整个列表以找到它;很明显,对于有很多键的对象来说,这会非常低效。因此,优化的JS引擎会做一些更聪明的事情 - 它可能按字母顺序存储密钥,因此它可以对密钥执行二进制搜索;或者更可能的是,它将使用一些散列函数并按此排序,以便二进制搜索更有可能达到最佳效率。
对于小型对象,存在不同的效率问题:内存使用情况。理想情况下,一个对象将占用一个连续的内存块,在任何一侧被其他对象或数据包围。当您添加更多键或更长的值时,对象的内存需要增长,并且将整个事物移动到更大的空间将会很慢并且在旧位置留下间隙,因此引擎需要做一些更聪明的事情。这可能包括预先分配额外空间以进入,并重新使用已删除项目腾出的空间(再次,这是一个最大化引擎效率的订单)。
所有这些都将根据特定情况在引擎内动态调整,其中包括键值对的数量和大小,甚至是对象的用途。因此,在重复删除和插入的影响下,超出一定规模并不会令人感到意外,现代浏览器会选择以相反顺序结束的策略。
底线不对对象中键的顺序做出任何假设。就您的代码而言,它们实际上是随机顺序。