我们应该hasOwnProperty()
在迭代对象的键时使用,因为Object.prototype
可能会被污染,通过原型继承,也会污染所有对象的键。
因此,如果我不污染Object.prototype
,我应该能够跳过hasOwnProperty()
减慢for-in 循环的过程。它还将使代码更简单。
思路:先检查Object.prototype
没有污染,再不要使用hasOwnProperty()
。
未污染的检查Object.prototype
由以下功能完成。我将在我的代码中的一个战略位置调用它,它在脚本执行期间偶尔执行(就像在我要处理一堆数据之前)。如果对以下方面做了任何不好的事情,此功能只是提醒我Object.prototype
:
/* jshint -W089 */ // http://jslinterrors.com/the-body-of-a-for-in-should-be-wrapped-in-an-if-statement/
var checkObjectPrototypeNotAugmented = function() {
/* jshint unused:false */ // Because key is considered unused
// Check if there is any enumerable property on Object.prototype:
for(var key in Object.prototype) {
throw new Error("Object.prototype has been augmented with keys: " + Object.prototype.keys());
}
};
注意:我/* jshint -W089 */
发表评论是为了让 jshint 不会抱怨缺少hasOwnProperty()
.
问:这样可以吗?还有什么我应该注意的吗?或者我可以改进?
现在一些基准:
以下是 3 个 jsPerf 基准测试,它们显示了具有不同属性数量的对象的增益:
- 1 个属性:使用 1 个属性迭代普通对象的自己的键
- 10 个属性:用 10 个属性迭代普通对象的自己的键
- 100 个属性:迭代具有 100 个属性的普通对象的自己的键
注意:Object.prototype
每次迭代对象的属性时都会执行检查。在实际情况下,测试只需要执行一次:当整个页面加载时(然后不时确保没有脚本被无意修改Object.prototype
)。因此,在实际情况下,您将获得“参考”测试的性能。但这表明,即使总是执行测试,它也保持得更快。
有趣的结果:
- 不使用
hasOwnProperty()
任何一个都可以提供相同的速度或更快,具体取决于浏览器 - 即使仅访问 1 个属性,
Object.protoype
在某些浏览器中,在每个 for-in 循环之前检查也可能比hasOwnProperty()
! (但我不建议总是这样检查Object.prototype
)
相关:我们还看到,Object.keys()
在某些浏览器中,对于大对象的使用速度可能更快,但对于小对象,它也可能更慢。但是使用Object.keys()
会迫使您要么只支持浏览器 >= IE 9,要么在 IE <= 8 中Object.prototype
添加一个polyfill。因此,为了与旧浏览器兼容,您必须选择Object.keys()
或checkObjectPrototypeNotAugmented()
。