for...in 会遍历对象自身及继承的可枚举属性,需用 hasownproperty 过滤;更推荐 object.keys() + for...of,它只返回自身可枚举属性,避免原型污染影响。

使用 for...in 遍历对象时,它会枚举**所有可枚举的自身属性和继承属性**,包括数组原型(如 Array.prototype)上被意外添加的扩展方法(比如通过 Array.prototype.myMethod = function(){} 添加的)。要忽略这些继承来的、非自身的属性,关键在于用 hasOwnProperty 做过滤。
只遍历对象自身的可枚举属性
这是最常用也最直接的方式:在循环体内检查当前键是否属于对象自身,而非从原型链继承。
示例:
const obj = { a: 1, b: 2 };
// 假设有人污染了 Array.prototype
Array.prototype.customLog = function() {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key]); // 只输出 'a' 和 'b'
}
}
用 Object.keys() + for...of 替代(更推荐)
Object.keys() 返回的是对象**自身可枚举属性的字符串数组**,天然不包含原型上的属性,语义更清晰、行为更可控。
- 不会遍历原型链上的任何属性(无论是否可枚举)
- 返回顺序与
for...in一致(ES2015+ 规范保证) - 配合
for...of或forEach更易读
示例:
const obj = { x: 10, y: 20 };
Array.prototype.badMethod = () => {};
for (const key of Object.keys(obj)) {
console.log(key, obj[key]); // 只输出 'x' 和 'y'
}
注意:for...in 本身不区分“对象”或“数组”
for...in 的行为只取决于操作数的类型和属性特性,和变量名无关。即使你用一个数组字面量 [1,2,3] 赋值给变量,for...in 仍会遍历它的索引("0", "1", "2")以及原型上所有可枚举属性(包括被污染的扩展方法)。
- 数组也是对象,所以
Array.prototype上的可枚举方法会被for...in捕获 - 现代 JS 中,原生数组方法(如
push、map)默认是不可枚举的,所以通常不会出现;但手动添加的扩展方法若没设enumerable: false,就会被遍历到
进阶:彻底避免原型污染影响(防御性写法)
如果运行环境不可控(比如第三方库可能污染原型),可以结合 Object.getOwnPropertyNames() 或 Reflect.ownKeys() 获取所有自身属性(含不可枚举的),再手动过滤出可枚举的:
const ownKeys = Reflect.ownKeys(obj);
for (const key of ownKeys) {
if (obj.propertyIsEnumerable(key)) {
console.log(key, obj[key]);
}
}
不过日常开发中,Object.keys() + for...of 已足够安全简洁。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











