应避免直接用 for...in 检查属性存在,因其遍历原型链易引发隐患;推荐用 Object.prototype.hasOwnProperty.call(obj, key) 过滤,或改用 Object.keys() + for...of 遍历自身可枚举属性。

直接用 for...in 检查属性存在,却没过滤原型链,是常见隐患。第三方库(比如 Lodash、jQuery 甚至某些 polyfill)常向 Object.prototype 或构造函数原型上挂方法(如 .each、.extend),一旦被 for...in 遍历出来,就可能触发非预期逻辑、类型错误或 ESLint 报错(如 for..in loops iterate over the entire prototype chain)。
用 hasOwnProperty 做基础过滤
这是最通用、兼容性最好的方式,能准确区分“对象自己有的属性”和“从原型继承来的”。注意必须用 Object.prototype.hasOwnProperty.call(obj, key) 调用,避免对象自身重写了 hasOwnProperty 导致失效:
for (let key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { /* 安全使用 key */ } }- 不要写
obj.hasOwnProperty(key)—— 若obj是空对象或原型被污染过,这个方法可能不存在或被覆盖
改用 Object.keys() + for...of 替代 for...in
如果目标只是检查或遍历对象自身的可枚举属性(绝大多数场景都是),直接避开 for...in 更干净:
for (const key of Object.keys(obj)) { /* key 肯定是 obj 自身属性 */ }- 需要值时用
Object.entries(obj),需要所有属性(含不可枚举?不推荐)时再考虑其他方案 - TypeScript 和 ESLint 默认鼓励这种写法,不会报原型链警告
提前冻结或清理污染的原型(针对第三方库)
某些老库会直接修改 Object.prototype,导致所有对象都带上额外属性。可在项目入口加一段防护:
- 运行时检测并删除:例如
if (Object.prototype.hasOwnProperty('forEach')) delete Object.prototype.forEach;(慎用,需确认不影响依赖) - 构建时用 Webpack/Babel 插件屏蔽原型污染代码,或换用不污染原型的现代替代库(如用
lodash-es而非lodash) - 开发阶段开启 ESLint 规则
no-extend-native,禁止修改原生原型
本质不是“怎么让 for-in 不出错”,而是“不该用 for-in 做属性存在性检查”。用对方法,问题就消失了。

















