为什么Microsoft IE会在插入/删除时更改对象键的顺序?

时间:2015-05-16 17:33:04

标签: javascript internet-explorer

对于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对象时,排序并不重要。

1 个答案:

答案 0 :(得分:2)

首先,这不是一个JSON对象,它是一个JS对象。 JSON是一种序列化格式,用于传递包含编码数据的文本字符串; JS中的对象是一个实际的对象,而不是一个对象的字符串表示。

其次,JS对象(以及发生的JSON对象)被明确定义为无序的键值对。您可以迭代它们,但不能依赖于以任何特定顺序获取元素。

JS的简单实现只是将每个新的键值对添加到列表的末尾。但这意味着无论何时访问特定密钥,都必须搜索整个列表以找到它;很明显,对于有很多键的对象来说,这会非常低效。因此,优化的JS引擎会做一些更聪明的事情 - 它可能按字母顺序存储密钥,因此它可以对密钥执行二进制搜索;或者更可能的是,它将使用一些散列函数并按此排序,以便二进制搜索更有可能达到最佳效率。

对于小型对象,存在不同的效率问题:内存使用情况。理想情况下,一个对象将占用一个连续的内存块,在任何一侧被其他对象或数据包围。当您添加更多键或更长的值时,对象的内存需要增长,并且将整个事物移动到更大的空间将会很慢并且在旧位置留下间隙,因此引擎需要做一些更聪明的事情。这可能包括预先分配额外空间以进入,并重新使用已删除项目腾出的空间(再次,这是一个最大化引擎效率的订单)。

所有这些都将根据特定情况在引擎内动态调整,其中包括键值对的数量和大小,甚至是对象的用途。因此,在重复删除和插入的影响下,超出一定规模并不会令人感到意外,现代浏览器会选择以相反顺序结束的策略。

底线不对对象中键的顺序做出任何假设。就您的代码而言,它们实际上是随机顺序。