for-in遍历对象及其原型链上所有非symbol、可枚举属性的键名;它不遍历值,会包含继承属性,易导致污染,需用hasownproperty过滤,现代开发更推荐object.keys()或object.entries()。

for-in 循环遍历的是对象所有可枚举属性的键名(key),不是值,也不限于自身属性——它会顺着原型链往上找,这是最常踩坑的根源。
它到底在遍历什么
for-in 遍历的是对象及其整个原型链上所有 可枚举(enumerable: true)且非 Symbol 类型 的属性名。比如:
- 普通对象自身的
name、age会被遍历到; - 如果
Array.prototype.customMethod是可枚举的,哪怕你遍历的是一个数组,它也会出现; -
Object.prototype.toString默认可枚举,所以也常被意外遍历出来; - 用
Object.defineProperty(obj, 'hidden', { enumerable: false })定义的属性,不会出现在 for-in 中。
常见误用场景
把 for-in 当作“取值工具”或“数组遍历器”,容易写出语义错误、行为不稳定甚至报错的代码:
- 对数组用 for-in:得到的是字符串索引
"0"、"1",不是元素值,可读性差,还可能混入原型方法; - 没加
hasOwnProperty判断:遍历到toString或第三方库挂载的原型属性,导致逻辑异常; - 误用点号访问:
obj.key写成obj[key]才对,因为 key 是变量,不是字面量; - 以为它按插入顺序遍历:ES2015 后数字键优先排序,但混合字符串键时顺序仍不完全可控,不适合依赖顺序的业务逻辑。
怎么安全地用 for-in
只在明确需要“检查对象是否为空”或“需兼容老环境且确定原型干净”时使用,并务必做防护:
- 始终配合
obj.hasOwnProperty(key)过滤继承属性; - 判空推荐写法:
for (let k in obj) { if (obj.hasOwnProperty(k)) return false; } return true;; - 避免在循环中增删属性:JS 引擎可能跳过刚删除或新增的属性,行为不可靠;
- 现代替代方案更推荐:
Object.keys(obj).forEach()或for (const [k, v] of Object.entries(obj)),它们只操作自身属性、顺序明确、语义清晰。
为什么现在少用了
不是 for-in 本身坏了,而是它的隐式行为太重:
- 默认包含原型链 → 容易污染结果;
- 不返回值,不能链式调用 → 无法像
Object.keys().map()那样组合操作; - 无法直接解构键值对 → 每次要手动写
obj[key]; - 性能上无优势,V8 等引擎对
Object.keys做了深度优化,实际更快更稳定。











