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

Why does Microsoft IE change the order of an object's keys on insertion/deletion?

本文关键字:对象 改变 顺序 删除 IE Microsoft 插入 为什么      更新时间:2023-09-26

对于Microsoft IE,如果插入一个键被删除且元素总数大于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对象时,顺序并不重要。

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

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

JS的一个简单实现只是将每个新的键值对添加到列表的末尾。但这意味着无论何时访问一个特定的键,都必须搜索整个列表才能找到它;显然,对于具有大量键的对象,这将变得非常低效。因此,优化后的JS引擎会做一些更聪明的事情——它可能会按字母顺序存储键,这样它就可以对键执行二进制搜索;或者更有可能的是,它会使用一些哈希函数并按其排序,这样二分查找更有可能达到最佳效率。

对于小对象,有一个不同的效率问题:内存使用。理想情况下,一个对象应该占用一个连续的内存块,其两侧被其他对象或数据包围。当你添加更多键或更长的值时,对象的内存需要增长,将整个对象移动到更大的空间会很慢,并且在旧位置留下空隙,所以引擎需要做一些更聪明的事情。这可能包括预先分配额外的空间来生长,并重用删除项腾出的空间(同样,以最大化引擎效率的顺序)。

所有这些都将根据特定情况在引擎内部动态调整,这将包括键值对的数量和大小,甚至对象的用途。因此,在重复删除和插入的影响下,超过一定大小,现代浏览器会选择以相反顺序结束的策略,这一点也不奇怪。

底线是不要对对象中的键的顺序做任何假设。就你的代码而言,它们的有效顺序是随机的。