Javascript:在使用“for”迭代对象时删除属性是否安全?

6
我正在做这样的事情:

我正在进行类似于以下的操作:

var myObj = {a:1, b:2, c:3, d:4};

for (var key in myObj){
  if (someCondition){
    delete(myObj[key]);
  }
}

我尝试的样例中运行良好,但是我不确定在某些情况/浏览器下是否会出现意外行为。

修改被迭代的对象是否可以?


1
过去我的经验表明,这可能会在IE7和8中出现问题。我发现大多数浏览器在迭代之前会“快照”键,而IE7/8似乎会“实时”使用它们。 - Matt Greer
我会看一下这篇文章:http://stackoverflow.com/questions/8538907/javascript-delete-method。它有一些关于delete的好链接。他正在遍历一个数组,而不是对象属性,但了解`delete`如何修改对象可能会有所帮助。 - DBueno
@MattGreer:这是针对删除属性还是添加属性? - user1106925
对我来说,添加属性是个问题。总的来说删除似乎更安全(规范也支持),但如果是我,我仍然会对IE7/8进行充分测试。 - Matt Greer
@MattGreer:是的,这总是一个好建议。我记得在添加属性时遇到过IE问题。似乎它们总是被添加到未枚举集合中,这可能不是不正确的,但与其他实现不同。这也会导致属性“替换”变成无限循环。 - user1106925
2个回答

8

第12.6.4节解释了for..in是基于“下一个属性”定义的:

令P为obj的下一个[[Enumerable]]属性为true的属性名称。如果没有这样的属性,返回(normal,V,empty)。

由于即使在突变的情况下,“下一个属性”的概念也是明确定义的(尽管迭代顺序不一定相同),因此在迭代过程中使用delete不会引入未定义行为。

有一种特殊情况,delete可以取消掩盖原型属性,例如

var obj = Object.create({ x: 1 });
obj.y = 2;
obj.x = 3;
for (var k in obj) {
  if (k == 'y') { delete obj.x; }
  alert(k);
}

在这种情况下,你可能需要遍历y并删除x,你仍然应该看到原型中的x,但如果你先遍历x,然后再遍历y,你就不应该看到第二个x

6

是的,它是安全的。

http://es5.github.com/#x12.6.4

12.6.4 for-in语句

列举属性的机制和顺序(在第一个算法中的步骤6.a,在第二个算法中的步骤7.a)未被指定。正在枚举的对象的属性可能会在枚举过程中被删除。如果删除了尚未在枚举过程中访问过的属性,则不会访问该属性。 如果在枚举期间向正在枚举的对象添加新属性,则不能保证将访问新添加的属性。任何枚举中都不能多次访问属性名称。


这指的是“属性”,而不是“属性名称”。请参见我回答中指定的边角情况,了解此区别的重要性。 - Mike Samuel

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