在迭代对象属性时删除一个对象属性是否安全?

129

当迭代一个对象的属性时,能否在 for-in 循环中安全地删除它们?

例如:

for (var key in obj) {
    if (!obj.hasOwnProperty(key)) continue;

    if (shouldDelete(obj[key])) {
        delete obj[key];
    }
}

在许多其他编程语言中,循环遍历数组或字典并在其中删除不是安全的。在JavaScript中可以这样做吗?

(我正在使用Mozilla的Spidermonkey运行时。)


我已经在这个问题上开始了悬赏,因为我认为当前的答案是不充分的,没有按照提出的问题进行回答。如果适用的话,请还要包括相关来源(最好来自规范)和任何值得注意的浏览器“怪异行为”。 - user2864740
2个回答

142

根据 ECMAScript 5.1 标准 的第12.6.4节 (有关于 for-in 循环) 规定:

在枚举对象的属性时,这些属性可能会被删除。如果删除了一个尚未被访问过的属性,则该属性不会被访问到。如果在枚举期间向正在枚举的对象中添加新属性,则不能保证新添加的属性将在主动枚举中被访问到。任何枚举中的属性名都不应该被多次访问。

所以我认为 OP 的代码是合法的并且会按预期工作。浏览器的怪异行为会影响迭代顺序和 delete 语句的一般情况,但并不影响 OP 的代码是否能够工作。通常最好只删除迭代对象的当前属性,而删除对象中的其他属性将不可预测地导致它们在迭代中被包含(如果已经访问)或不包含在迭代中,尽管这可能或可能不是一个问题,具体取决于情况。

另请参见:

然而,这些都不会影响 OP 的代码。


20

来自Javascript/ECMAScript规范(特别是12.6.4 for-in语句):

在枚举期间,正在枚举的对象的属性可能会被删除。如果在枚举期间删除了尚未访问过的属性,则不会访问该属性。如果在枚举期间向对象添加了新属性,则无法保证在活动枚举中会访问到新添加的属性。每个属性名在任何枚举中都不得被访问多次。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接