我注意到,在枚举对象的属性时,似乎是在循环开始时获取当前属性的快照,然后迭代快照.我觉得这样,因为以下不会创建无限循环:
var obj = {a:0,b:0}, i=0;
for (var k in obj) {
obj[i++] = 0;
}
alert(i) // 2
Run Code Online (Sandbox Code Playgroud)
上面的代码演示了我正在添加新属性,但新属性不会被枚举.
但是,删除操作符似乎违反了我的快照理论.这是相同的代码,但在枚举之前删除属性.
var obj = {a:0,b:0}, i=0;
for (var k in obj) {
i++;
delete obj.b;
}
alert(i) // 1
Run Code Online (Sandbox Code Playgroud)
上面的代码演示了循环体只执行了一次.如果快照理论是真的,它会执行两次.
这里发生了什么?javascript是否具有它使用的某种类型的隐藏迭代器,并且delete运算符在某种程度上意识到它?
- 我意识到我正在假设有关迭代顺序的事情 - 特别是基于属性插入时间发生迭代.我相信所有浏览器都使用这样的实现.
有趣的问题.答案在于规范(强调我的):
枚举属性的机制和顺序(第一个算法中的步骤6.a,第二个算法中的步骤7.a)未指定.枚举期间可以删除要枚举的对象的属性.如果删除枚举期间尚未访问的属性,则不会访问该属性.如果在枚举期间将新属性添加到要枚举的对象,则无法保证在活动枚举中访问新添加的属性.在任何枚举中不得多次访问属性名称.
因此明确指出不得再遍历已删除的属性.但是,添加新属性的行为取决于实现,很可能是因为未定义属性应如何在内部存储.
例如,在Chrome中,似乎数字属性按字母顺序存储:
> Object.keys({a:0, 0:1});
["0", "a"]
Run Code Online (Sandbox Code Playgroud)
但是,即使您添加字母键:
var obj = {a:0,b:0};
for (var k in obj) {
obj['c'] = 0;
console.log(k);
}
Run Code Online (Sandbox Code Playgroud)
c似乎没有被遍历,输出是a b.
Firefox显示相同的行为,尽管密钥以插入顺序存储:
> Object.keys({a:0, 0:1});
["a", "0"]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
240 次 |
| 最近记录: |