Object.hasOwn是ES2022引入的静态方法,用于安全检测对象自有属性;hasOwnProperty是依赖原型链的实例方法,存在被覆盖、null/undefined报错及原型污染风险。

Object.hasOwn 是 ES2022 引入的静态方法,用于安全检测对象是否拥有某个自有属性;hasOwnProperty 是从 Object.prototype 继承的实例方法,依赖对象自身的原型链和方法实现。两者语义一致,但底层机制和安全性差异显著。
核心区别:调用方式与安全性
hasOwnProperty 必须通过对象实例调用(如 obj.hasOwnProperty('key')),因此容易受三类干扰:
- 对象自身重写了
hasOwnProperty方法(例如{ hasOwnProperty: () => false }),导致结果始终错误 - 对象未继承该方法(如
Object.create(null)创建的对象),调用直接抛TypeError - 原型链被污染(如
Object.prototype.hasOwnProperty = null),所有继承该原型的对象都会失效
Object.hasOwn 是静态方法(Object.hasOwn(obj, 'key')),它绕过目标对象的原型和自身属性,始终调用 Object.prototype.hasOwnProperty 的原始实现,不依赖任何运行时状态。
行为差异:null/undefined 和 Symbol 支持
Object.hasOwn 对非对象参数(如 null、undefined)会明确返回 false,无需额外判空;而 obj?.hasOwnProperty?.('key') 在原型被篡改时仍可能报错,且不能覆盖 Object.create(null) 场景。
两者都支持 Symbol 类型键(Object.hasOwn(obj, sym) 或 obj.hasOwnProperty(sym)),但 Object.hasOwn 更健壮——它不触发对象上可能存在的 getter,也不因键名类型转换出错。
旧环境兼容方案
现代运行时(Chrome 93+、Firefox 92+、Safari 15.4+、Edge 93+、Node.js 16.9+)已原生支持。若需支持更早版本,可添加轻量 polyfill:
if (!Object.hasOwn) {
Object.hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
}
注意:这个 polyfill 仍依赖 Object.prototype.hasOwnProperty 未被污染。如需更强防护(例如对抗原型链污染),可进一步加固:
- 先用
Object(obj)将非对象转为对象(避免null/undefined报错) - 再调用
Object.prototype.hasOwnProperty.call(Object(obj), key)
构建工具或 TypeScript 项目中,确保 tsconfig.json 的 "lib" 包含 "es2022" 或更高版本,否则类型检查可能报错。
什么场景必须优先替换
以下环节一旦出错后果严重,应立即迁移:
- 用户提交数据的字段白名单校验(如
if (Object.hasOwn(formData, 'email'))) - 第三方 SDK 返回对象的属性存在性判断
- 配置对象中显式设置项的识别(排除继承默认值)
- 序列化前对 key 的存在性断言
搭配 ESLint 的 no-prototype-builtins 规则,能自动捕获残留的 hasOwnProperty 调用,推动渐进式升级。


















