object.hasown 是 es2022 引入的安全、准确判断对象是否拥有自有属性的静态方法,适用于不可信数据校验、配置对象判断、for...in 过滤、symbol 键检测及 object.create(null) 对象,但不支持非对象参数、map/set、属性描述符或可枚举性检查。

Object.hasOwn 是 ES2022 引入的标准化静态方法,核心定位是**安全、准确地判断对象是否拥有某个自有属性**。它不是万能工具,而是在特定边界内表现最优的“自有属性检测专家”。理解它的适用场景和限制,才能用得准、避得开坑。
适用范围:哪些地方它最值得用
它专为解决传统 hasOwnProperty 的安全隐患而生,最适合出现在以下环节:
-
不可信数据的字段校验:比如用户提交的 JSON、第三方 API 返回的对象、表单解析结果——这些对象可能被篡改原型或自身覆盖
hasOwnProperty,用Object.hasOwn(obj, 'email')可直接规避风险 -
配置对象的显式赋值判断:检查
config.timeout是否由开发者主动设置,而非继承默认值,!Object.hasOwn(config, 'timeout')比'timeout' in config更精准 -
for...in 循环中过滤继承属性:配合遍历使用,
for (const key in obj) { if (Object.hasOwn(obj, key)) { /* 处理自有属性 */ } }是当前最简洁可靠的写法 -
Symbol 类型键的存在性检测:支持传入原始 Symbol 值,
Object.hasOwn(obj, mySym)安全有效,而旧方法需额外注意类型一致性 -
Object.create(null) 创建的对象:这类无原型对象无法调用
hasOwnProperty,但Object.hasOwn完全兼容
局限性:它不负责、也不能做的事
它能力明确,边界清晰,以下情况不属于它的职责范畴:
-
不适用于非对象参数:传入
null或undefined会抛TypeError;字符串、数字等原始值也不行。需前置判断:obj != null && typeof obj === 'object' -
不处理 Map/Set 等集合类型:它们有自己的
.has()方法(如map.has(key)),混用Object.hasOwn无意义且报错 -
不替代 Reflect.has:后者行为类似
in操作符,用于检查“是否可访问”(含原型链),用途不同,不能互换 -
不检测属性的可枚举性或描述符状态:它只回答“是否存在自有属性”,不管是否
enumerable、是否writable,也不关心 getter/setter 是否定义 -
对数组索引的语义需留意:虽然
Object.hasOwn([1,2], '0')返回true,但它检测的是“索引 0 是否作为自有属性存在”,不是“数组长度是否 ≥ 1”——二者逻辑不同,勿混淆用途
兼容性与降级注意事项
现代环境已广泛支持,但落地时仍需留心:
- 原生支持范围:Chrome 93+、Firefox 92+、Safari 15.4+、Edge 93+、Node.js 16.9+
-
降级不能简单用 .call 绑定:
Object.prototype.hasOwnProperty.call仍依赖未被污染的Object.prototype,不够安全;推荐降级写法:Object.hasOwn || ((obj, key) => Object.prototype.hasOwnProperty.call(Object(obj), key)),其中Object(obj)能兜底null/undefined -
TypeScript 项目需配置:确保
tsconfig.json中"lib"包含"es2022"或更高版本,否则类型检查可能报错
和 in 操作符、Object.keys 的关键区别
三者常被拿来对比,但职责完全不同:
-
Object.hasOwn(obj, key):只查对象自身,不走原型链,语义聚焦“自有” -
key in obj:查整个原型链,回答“能否访问到”,易受原型污染影响,不满足“自有”需求 -
Object.keys(obj):返回所有自有可枚举属性名数组,性能开销大,不适合单次存在性判断











