for-in会遍历对象自身及原型链上所有可枚举属性,易受原型污染影响;应使用object.prototype.hasownproperty.call(obj, key)或object.hasown(obj, key)过滤,或优先选用object.keys()等更安全的遍历方式。

在 for-in 循环中遍历对象时,如果没做防护,会把原型链上可枚举的属性也一并列出——这是 JavaScript 中一个高频、隐蔽且容易被忽略的 Bug 来源。
明确 for-in 的行为边界
for-in 专门设计为遍历**对象自身 + 原型链上所有可枚举(enumerable)属性**。它不区分“是不是这个对象自己定义的”,只看是否可枚举、是否在原型链上存在。比如:
Object.prototype.customMethod = function() {}; // 全局污染
const obj = { a: 1 };
for (let key in obj) {
console.log(key); // 输出 "a" 和 "customMethod"
}
即使你没主动改 Object.prototype,第三方库或老旧代码也可能悄悄添加了可枚举方法,导致循环结果不可控。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
用 hasOwnProperty 过滤掉继承属性
最直接、兼容性最好、无需额外依赖的解法:在循环体内加一层判断,只处理对象自身的属性。
- 写法简洁:
if (obj.hasOwnProperty(key)) { ... } - 注意:不要用
obj.hasOwnProperty直接调用,以防对象自身重写了该方法;稳妥写法是Object.prototype.hasOwnProperty.call(obj, key) - ES6+ 中也可用
Object.hasOwn(obj, key)(Chrome 93+、Node.js 16.9+ 支持),更安全、更语义化
优先考虑更安全的遍历方式
如果你本意只是遍历对象自身的可枚举属性,for-in 其实不是最优选:
-
Object.keys(obj):返回自身可枚举属性名数组,天然不包含原型链属性,推荐作为默认方案 -
Object.getOwnPropertyNames(obj):包括不可枚举属性(如toString),按需使用 -
Object.entries(obj)或Object.values(obj):适合需要键值对或纯值的场景 - 配合
for-of使用更现代、更可控:for (const [key, val] of Object.entries(obj)) { ... }
警惕“看似安全”的误判场景
有些写法看似过滤了,实则仍有隐患:
- 写成
if (key in obj)—— 这个条件恒为真,完全无效 - 只检查
typeof obj[key] !== 'function'—— 无法区分是自身方法还是继承方法 - 用
for-of配合Reflect.ownKeys()却忘了Reflect.ownKeys包含不可枚举和 symbol 属性,可能漏掉预期中的可枚举属性 - 在类实例上遍历,却忘了 class 方法默认不可枚举,但 class 字段(public field)是可枚举的——需结合实际定义方式判断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










