in会查原型链,hasownproperty只查自有属性;object.hasown是更安全的替代方案;避免用object.keys().includes()遍历判断。

遍历对象属性时,in 和 hasOwnProperty 的行为差异核心在于“查不查原型链”——前者会,后者坚决不。
in 会把继承来的属性也当作“存在”
在 for...in 循环中直接用 key in obj 判断,结果包含所有可枚举的自有属性 + 原型链上可枚举的属性。比如:
- 你给
Object.prototype添加了.log方法,所有普通对象都会在for...in中遍历出'log'; - 用
class B extends A创建实例,父类原型上的方法名(如'getName')也会被in捕获; - 即使属性值是
undefined,只要键名在原型链某处声明过,in就返回true。
hasOwnProperty 是专为“过滤继承”设计的
它天然用来剔除原型链干扰,只认对象自己 {} 里定义的那些属性:
- 在
for...in循环内部加一层if (obj.hasOwnProperty(key)),就能只处理真正属于这个对象的数据字段; - 对
Object.create(null)创建的对象,必须用Object.prototype.hasOwnProperty.call(obj, key),否则会报错(因为没原型); - 它不关心属性是否可枚举,只要是在对象自身属性表里登记过的(包括不可枚举属性如
__proto__),就返回true。
现代推荐:优先用 Object.hasOwn 替代 hasOwnProperty
ES2022 引入的 Object.hasOwn(obj, key) 解决了两个老问题:
- 不用再写冗长的
call绑定,调用更简洁安全; - 即使对象自身意外覆盖了
hasOwnProperty(比如obj.hasOwnProperty = null),Object.hasOwn依然可靠; - 语义更清晰:“对象是否拥有该属性”,而不是“调用一个可能被污染的方法”。
别在遍历中用 Object.keys().includes()
有人想绕开原型问题,改用 Object.keys(obj).includes(key),但这在遍历场景下尤其不合适:
- 每次调用都新建数组,循环几十次就是几十个临时数组,触发频繁垃圾回收;
- 只返回可枚举自有属性,漏掉
Object.defineProperty设置的不可枚举字段; - 完全不兼容需要检查原型链的逻辑(比如判断某个方法能否被调用),语义错位。











