for-in 循环遍历对象自身及原型链上所有可枚举属性,因设计如此;要只遍历自身属性需用 hasownproperty 过滤,或改用 object.keys();注意数组慎用、避免修改原型、不可枚举属性和 symbol 属性均不被遍历。

for-in 循环默认会遍历对象自身及其原型链上所有可枚举(enumerable: true)的属性,包括从 Object.prototype 继承来的(如 toString、hasOwnProperty 等),但不包括不可枚举属性(如 constructor、__proto__)或 Symbol 属性。
为什么 for-in 会遍历原型链上的属性
这是 for-in 的设计行为:它遍历的是“对象可被枚举的属性集合”,这个集合由对象自身 + 整条原型链上所有可枚举自有属性共同构成。只要某个属性在原型链某一级是可枚举的,就会被列出。
例如:
const parent = { a: 1 };
Object.defineProperty(parent, 'b', { value: 2, enumerable: false });
const child = Object.create(parent);
child.c = 3;
for (let key in child) {
console.log(key); // 输出 'c' 和 'a'(因为 a 在 parent 上且 enumerable: true)
}
如何只遍历对象自身的可枚举属性
用 hasOwnProperty 方法过滤:
- 每个对象都继承自 Object.prototype,拥有 hasOwnProperty 方法
- 该方法返回 true 仅当属性是对象自身的(非继承)
- 推荐写法:
if (obj.hasOwnProperty(key)) { ... }
示例:
for (let key in child) {
if (child.hasOwnProperty(key)) {
console.log(key); // 只输出 'c'
}
}
如何排除原型链上所有可枚举属性(彻底隔离)
除了 hasOwnProperty,还可结合 Object.prototype.propertyIsEnumerable 或更现代的方式:
-
Object.prototype.propertyIsEnumerable.call(obj, key)判断该 key 是否为 obj 自身的可枚举属性(比 hasOwnProperty 更精确,因 hasOwnProperty 不区分 enumerable) - 更简洁安全的做法是使用 Object.keys(obj) 配合 forEach 或 for-of(它只返回自身可枚举字符串键)
- 若需兼容旧环境且必须用 for-in,坚持用 hasOwnProperty 是最常用、最稳妥的过滤方式
注意边界情况和常见陷阱
以下情况需特别留意:
- 数组慎用 for-in:它遍历的是索引字符串(如 "0", "1")和所有可枚举的自定义属性(包括原型上添加的),但不保证顺序,也不跳过稀疏空位;应优先用 for-of、forEach 或传统 for
- 修改原型(如给 Array.prototype 添加属性)会让所有数组实例在 for-in 中暴露该属性,可能引发意外遍历
- 不可枚举属性(通过 defineProperty 设置 enumerable: false)不会出现在 for-in 中,无论是否在原型链上
- Symbol 属性永远不被 for-in 遍历,哪怕可枚举;要用 Object.getOwnPropertySymbols()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











