【发布时间】:2011-03-08 13:03:23
【问题描述】:
这是一个古老的question,我知道在需要任何排序时不使用for..in 甚至对象的常见原因,但我最近从MDC 看到了这篇文章删除操作符。
跨浏览器问题
虽然 ECMAScript 使对象的迭代顺序依赖于实现,但似乎所有主流浏览器都支持基于最早添加的属性的迭代顺序(至少对于不在原型上的属性)。但是,在 Internet Explorer 的情况下,当对属性使用 delete 时,会导致一些令人困惑的行为,从而阻止其他浏览器使用像对象字面量这样的简单对象作为有序关联数组。在资源管理器中,虽然属性值确实设置为未定义,但如果稍后添加一个具有相同名称的属性,则该属性将在其旧位置迭代——而不是在迭代序列的末尾,正如人们可能期望的那样删除该属性,然后将其添加回来。
因此,如果您想在跨浏览器环境中模拟有序关联数组,则必须使用两个单独的数组(一个用于键,另一个用于值),或者构建一个单一属性的数组物体等。
似乎大多数主要浏览器 - Chrome、Safari、Firefox 和 Opera 都按插入顺序枚举对象属性。这是一个快速的test 来确认。它可能不适用于 IE,但不幸的是我无法访问 IE 来测试它。假设我们不从对象中删除任何内容,IE 在使用 for..in 迭代属性时是否也保留排序(6/7 起)?
此外,出于完全相同的原因,for..in 是 never 推荐用于遍历数组,事实上Array.prototype 比Object.prototype 更容易被篡改。但是,如果属性实际上是按插入顺序枚举的,那么我想for..in 也可以用于循环数组,具有以下问题-Array.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
});
如果满足上述所有条件,并且除非我遗漏了一些重要的东西,for..in 也可以安全地用于数组迭代:
var values = [1, 2, 3];
for(var i in values) {
values[i];
}
所以我想这又回到了最初的问题。不管规范怎么说,IE 是否支持任何版本的插入顺序对象迭代?是否还有其他浏览器不支持此功能。
【问题讨论】:
标签: javascript arrays object iteration