当排序很重要时,使用for..in迭代JavaScript对象属性和数组

当排序很重要时,使用for..in迭代JavaScript对象属性和数组,javascript,arrays,object,iteration,Javascript,Arrays,Object,Iteration,这已经有很长的历史了,我知道在需要任何排序时不使用for..in或甚至不使用objects的通常原因,但我最近在delete操作符上看到了这篇文章 跨浏览器问题 尽管ECMAScript使对象的迭代顺序依赖于实现,但似乎所有主要浏览器都支持基于最先添加的属性的迭代顺序(至少对于不在原型上的属性)。但是,在Internet Explorer中,当对属性使用delete时,会产生一些令人困惑的行为,从而阻止其他浏览器将简单对象(如对象文字)用作有序关联数组。在资源管理器中,虽然属性值确实设置为“未定

这已经有很长的历史了,我知道在需要任何排序时不使用for..in或甚至不使用objects的通常原因,但我最近在delete操作符上看到了这篇文章

跨浏览器问题 尽管ECMAScript使对象的迭代顺序依赖于实现,但似乎所有主要浏览器都支持基于最先添加的属性的迭代顺序(至少对于不在原型上的属性)。但是,在Internet Explorer中,当对属性使用delete时,会产生一些令人困惑的行为,从而阻止其他浏览器将简单对象(如对象文字)用作有序关联数组。在资源管理器中,虽然属性值确实设置为“未定义”,但如果稍后添加回具有相同名称的属性,则该属性将在其旧位置进行迭代——而不是在删除属性并将其添加回后,在迭代序列的末尾进行迭代

因此,如果要在跨浏览器环境中模拟有序关联数组,则必须使用两个单独的数组(一个用于键,另一个用于值),或者构建单个特性对象的数组,等等

大多数主流浏览器——Chrome、Safari、Firefox和Opera——似乎都按插入顺序枚举对象属性。这是一个很快证实这一点的例子。它可能无法在IE上运行,但不幸的是,我无法访问IE来测试它。那么IE在使用
for..in
对属性进行迭代时是否也保留了顺序(从6/7开始)

此外,出于完全相同的原因,
for..in
被推荐用于迭代数组,而且
Array.prototype
Object.prototype
更容易被篡改。但是,如果属性实际上是按插入顺序枚举的,那么我认为
for..in
也可以用于在数组上循环,下面的gotcha-属性列在
数组上。prototype
也将被枚举

有两种解决方案:

使用
hasOwnProperty

for(var index in object) {
    if(object.hasOwnProperty(index)) {
        ..
    }
}
使用新的ES5语法定义对象的属性,并使其不可枚举。这假设您完全控制基本原型的扩展,并且没有第三方代码直接在原型上添加任何内容

Object.defineProperty(Array.prototype, "size", {
    enumerable: false,
    configurable: false,
    get: function() { return this.length; },
    set: undefined
});
如果满足上述所有条件,并且除非我遗漏了一些关键的内容,否则,中的..也可以安全地用于数组迭代:

var values = [1, 2, 3];

for(var i in values) {
    values[i];
}

所以我想这又回到了原来的问题。不管规范怎么说,IE对任何版本都支持按插入顺序进行对象迭代吗?是否还有其他浏览器不支持此功能。

在WinXP pro SP2上的IE8上运行测试证实了MDC文章。IE8按照声明的顺序迭代成员;如果删除了一个现有属性,然后重新分配了它,那么它的原始迭代位置将保持不变。其他浏览器(我验证了Chrome 5和Firefox 3)将重新分配的属性放在迭代顺序的末尾。

在IE 5.5-6-7-8上显示了完全相同的行为。属性是有序的。已删除的属性保留其位置

但由于这是非标准行为,它可能会与IE9或任何浏览器的下一个版本发生冲突

也许我错过了什么,但重点是什么?与更健壮的代码相比,节省了一些字符,该代码在第三方广告、跟踪系统、小部件等方面运行良好


更不用说支持移动浏览器和市场份额很小的桌面浏览器了。

除了这里提到的浏览器之外,还有更多的浏览器:目前还有其他浏览器和未来的浏览器。当迭代对象的属性时,它们都没有义务实现任何排序,而且在很长一段时间内也不会实现,因为最近的ECMAScript 5没有指定排序。事实上,尽管有人要求它与其他浏览器保持一致


基于当前少数浏览器的观察行为的任何假设充其量都是不可靠的;正如所观察到的,并非所有当前浏览器的行为都相同,未来的浏览器可能会选择不符合您的假设,并且完全有权这样做。因此,我强烈建议您不要依赖任何代码中的任何特定顺序。

谢谢@maerics-这非常有用。如果IE 6/7也表现出同样的行为,那就太好了。谢谢你详尽的IE测试。只要我们意识到不同浏览器的行为,我不认为这不能与第三方代码共存。至于为什么它很重要,有许多使用有序关联数组的用例。您可以查看此问题以了解更多详细信息。如果需要更强大的删除功能,我们当然可以编写自己的
OrderedMap
LinkedMap
实现,但对于只读列表,它只起作用:)