for...in 遍历对象时需用 hasOwnProperty 过滤原型属性,或更推荐用 Object.keys + for...of;它只返回自身可枚举字符串键,避免原型污染和顺序问题。

用 for...in 遍历对象时,必须过滤掉原型链上的属性,否则容易误读继承来的可枚举属性(比如从 Object.prototype 或自定义父类继承的方法)。核心原则是:只处理对象**自身**的可枚举属性。
检查 hasOwnProperty
最常用且可靠的方式是配合 hasOwnProperty 方法判断属性是否属于对象自身:
const obj = { a: 1, b: 2 };
obj.toString = function() {}; // 覆盖了原型上的 toString,但仍是自身属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key, obj[key]); // 只输出 'a' 1 和 'b' 2
}
}
-
hasOwnProperty是Object.prototype上的方法,它返回布尔值,表示该属性是否直接存在于对象上 - 注意:如果对象自身重写了
hasOwnProperty(比如obj.hasOwnProperty = null),这个方法会失效——此时应使用Object.prototype.hasOwnProperty.call(obj, key)更稳妥
用 Object.keys + for of 替代(推荐)
现代 JavaScript 中,更清晰、更安全的做法是先获取自身可枚举属性名数组,再遍历:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
const obj = { x: 10, y: 20 };
Object.prototype.z = 30; // 添加到原型上(不推荐,但用于演示)
for (const key of Object.keys(obj)) {
console.log(key, obj[key]); // 只输出 'x' 10 和 'y' 20
}
-
Object.keys()返回一个仅包含对象**自身可枚举属性名**的数组,天然避开原型链 - 配合
for...of语义明确,代码可读性高,也避免了for...in对数组索引顺序不确定、对稀疏数组行为异常等问题 - 若需同时访问键和值,可用
Object.entries(obj)
注意 for...in 的其他陷阱
for...in 本身不保证遍历顺序,且会遍历所有可枚举属性(包括字符串键、Symbol 键?不,Symbol 不会被 for...in 遍历):
- 遍历顺序:ES2015+ 规定数字键按升序,其余键按添加顺序;但不同引擎早期实现可能有差异,不应依赖顺序
- 不会遍历 Symbol 类型属性(哪怕可枚举),如需遍历 Symbol 属性,要用
Object.getOwnPropertySymbols()或Reflect.ownKeys() - 不要用
for...in遍历数组 —— 它遍历的是“属性名”,不是数值索引,且会把数组的额外属性(如arr.custom = 'x')也列出来
需要遍历包括 Symbol 的所有自身键?用 Reflect.ownKeys
如果业务要求获取对象全部自身键(含字符串、Symbol、不可枚举),再筛选可枚举的,可以用:
const obj = { a: 1 };
obj[Symbol('b')] = 2;
Object.defineProperty(obj, 'c', { value: 3, enumerable: false });
const ownKeys = Reflect.ownKeys(obj);
for (const key of ownKeys) {
if (obj.propertyIsEnumerable(key)) {
console.log(key, obj[key]);
}
}
-
Reflect.ownKeys(obj)返回所有自身键(字符串 + Symbol) -
propertyIsEnumerable(key)判断该键是否为可枚举属性(比hasOwnProperty更精确,因它还考虑了enumerable描述符) - 这种组合适合高级场景,日常开发中
Object.keys已覆盖绝大多数需求
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










