我最近偶然发现了在JavaScript中使用for..in循环的问题。
根据this问题中的答案,for..in旨在枚举对象的属性,包括继承的属性。
如果是这样,为什么我们能够使用Object.defineProperty将属性定义为不可枚举?这不符合for..in的全部意图吗?或者它被认为是不好的做法,应该避免?
另外,为什么我们要首先以这种方式迭代所有属性(即使用for..in循环)?什么时候可以派上用场?
为什么不将所有(Array)原型扩展定义为不可枚举并继续在数组中使用for..in?
答案 0 :(得分:6)
问题是对象属性只有一个命名空间(暂时忽略ES2015中的符号功能)。您做的某些对象属性想要枚举,而有些属性不是。包含对象数据和与其他对象的关系的属性与方法名称共享该命名空间。
for ... in
循环不仅会查看直接涉及的对象的属性,还会查看原型链的属性。这可能最有可能用于非可枚举的属性:您可能希望放在原型对象上的方法可能不需要是可枚举的。
对我来说,当您在迭代Array实例的数字名称属性时不使用for ... in
的真正原因是,无法保证您将遍历任何特定顺序的索引。虽然大多数运行时系统做以明显的顺序返回数字名称属性,但该语言的规范绝对不需要这样。通过在普通for
循环中使用显式数字索引,您可以显式控制迭代顺序。
编写JavaScript代码以供在其无法控制的其他代码运行的情境中使用的人(想想广告支持的网站或具有大量指标工具的网站)知道依赖于内置原型不受随机垃圾的污染是非常不明智的。使用for ... in
会使您的代码受到对第三方代码做出贡献的最差编码器的支配。
现代实现有Object.keys()
,它返回可枚举的"拥有的"对象的属性名称;也就是说,直接在对象上的属性名称,而原型链中没有属性。