object.hasown是es2022引入的静态方法,用于安全、准确检测对象自有属性,替代易被覆盖或失效的hasownproperty;它绕过原型链、支持symbol、仅查自身属性,且在chrome 93+等现代环境原生支持。

Object.hasOwn 是 ES2022 正式引入的静态方法,专为安全、准确判断对象“自有属性”而设计。它不是语法糖,而是对传统 hasOwnProperty 根本性缺陷的修复方案。在现代项目中,只要目标环境支持(Chrome 93+、Firefox 92+、Safari 15.4+、Node.js 16.9+),就应默认使用它替代所有 obj.hasOwnProperty() 场景。
适用场景:哪些地方必须换掉 hasOwnProperty
以下情况一旦继续用 hasOwnProperty,就存在运行时风险或逻辑错误:
-
处理不可信数据:用户输入、第三方 API 返回、JSON 解析结果等可能被恶意构造(如覆盖
hasOwnProperty方法或使用Object.create(null)) -
遍历对象时过滤原型属性:配合
for...in循环,避免继承属性干扰(如toString、constructor或库注入的原型方法) -
配置对象校验:检查必填字段是否存在且为自有属性(
if (!Object.hasOwn(config, 'timeout')) config.timeout = 5000) -
解构前兜底判断:防止因属性缺失导致解构报错,例如
const { name } = user; → if (Object.hasOwn(user, 'name')) { ... } -
Symbol 键检测:
Object.hasOwn(obj, Symbol('id'))安全有效,而obj.hasOwnProperty(Symbol('id'))在部分旧引擎中行为不一致
性能对比与关键事实
很多人关心“会不会变慢”,实际测试表明:Object.hasOwn 和优化后的 Object.prototype.hasOwnProperty.call() 性能几乎完全一致,远优于反复调用 Object.keys(obj).includes(key)(后者需构建新数组)。真正影响性能的不是方法本身,而是误用方式:
-
别用
Object.keys(obj).includes(key)替代:每次调用都触发完整枚举 + 数组创建 + 线性查找,O(n) 时间复杂度 -
别依赖
key in obj做自有属性判断:它查原型链,语义不符,且无法区分obj.toString(继承)和obj.toString = ...(自有) -
避免重复调用:若需多次检测同一对象的多个属性,可先用
Object.keys(obj)或Object.getOwnPropertyNames(obj)缓存键集合,再做includes—— 仅适用于批量判断场景
边界处理与类型安全
Object.hasOwn 对参数类型敏感,这是它的设计特性,不是 bug:
-
只接受对象:传入
null、undefined、字符串、数字会直接抛TypeError,因此需前置校验:obj != null && typeof obj === 'object' -
不兼容 Map/Set:它们有自己的
.has()方法,混用会出错 -
不替代 Reflect.has:后者语义等价于
in,用于需要检查原型链的场景(如 Proxy 中的 trap) -
TypeScript 用户注意:确保
tsconfig.json中"lib"包含es2022或更高版本,否则类型定义缺失
兼容性兜底方案(仅必要时)
若项目仍需支持较老环境(如 IE 或 Node.js
const hasOwn = Object.hasOwn || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
// 使用方式不变
if (hasOwn(obj, 'name')) { ... }
不建议用 polyfill 模拟 Object.hasOwn 的全部语义(尤其对 Object.create(null) 的支持),简单绑定已覆盖 99% 场景。











