如同 in
运算符一样,使用 for in
循环遍历对象属性时,也将往上遍历整个原型链。
// Poisoning Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
console.log(i); // prints both bar and moo
}
这里我们要注意两点,一是 for in
循环会忽略 enumerable
设置为 false
的属性。例如一个数组的 length
属性。第二是,由于 for in
会遍历整个原型链,所以当原型链过长时,会对性能造成影响。
enumerable
是个很陌生的词汇,实际上,你很难在javascript
中发现它的影子,而它实际上也是作者从ruby
中借鉴而来的。创建enumerable
的目的不是为了独立使用,而是采用“混用”的方式,而Prototype
中很多方法都混用了enumerable
,所以它可以说是prototype
的奠基石。这里不做详细介绍,详细内容可以参考 - Enumerable。
由于我们没法改变 for in
循环本身的行为,所以我们只能采取其他方法来过滤掉那些不希望出现在循环内的属性,通过 《细说 Javascript 对象篇(三) : hasOwnProperty》 我们知道 hasOwnProperty
方法是可以做到这一点的。
使用 hasOwnProperty 过滤
仍然使用上个例子:
// Poisoning Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}
这是唯一正确的写法,由于我们实用了 hasOwnProperty
方法,所以这次只输出 moo
。如果不适用 hasOwnProperty
方法,那么当 Object.prototype
扩展时,就会出现错误。
现在很多框架都会选择从 Object.prototype
扩展方法,所以我们使用这些框架时,如果使用没有用 hasOwnProperty
过滤的 for in
循环时就会遇到问题。
总结
建议养成 hasOwnProperty
过滤属性的好习惯,不要对运行环境做任何假设,也无论原生的原型对象是否被扩展。
参考
http://bonsaiden.github.io/JavaScript-Garden/#object.forinloop
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。