如何用 Object.hasOwn 替代 hasOwnProperty 提升代码的健壮性

作者:袖梨 2026-07-18
Object.hasOwn是ES2022引入的静态方法,用于安全检测对象自身是否拥有指定属性,替代易受原型污染影响的hasOwnProperty;它不依赖对象原型、支持null/undefined、参数顺序为(obj, prop),且类型更精确。

Object.hasOwn 是什么,为什么能替代 hasOwnProperty

Object.hasOwn 是 ES2022 正式引入的静态方法,用于检测对象自身是否拥有指定属性(不查找原型链)。它本质是 hasOwnProperty 的安全替代品,核心区别在于:后者是继承自 Object.prototype 的实例方法,而对象可能被篡改——比如原型上覆盖了 hasOwnProperty,或对象本身冻结/不可扩展但又没有该方法(如 Object.create(null))。

常见错误现象:{}.hasOwnProperty.call(null, 'x')TypeError: Cannot convert null to object;而 Object.hasOwn(null, 'x') 安全返回 false

  • Object.hasOwnnullundefined 等非对象值自动返回 false,无需额外类型检查
  • 它不依赖对象自身的 hasOwnProperty 方法,绕过原型污染风险
  • Object.create(null) 创建的对象上可直接使用,无需手动绑定或兜底

哪些场景必须用 Object.hasOwn 替代 hasOwnProperty

当处理不可信输入、动态构造对象或与第三方库交互时,hasOwnProperty 很容易失效。典型场景包括:解析用户提交的 JSON、遍历 Map.prototype.toJSON() 返回的对象、操作由 ProxyObject.assign 生成的扁平对象。

  • 遇到 TypeError: xxx.hasOwnProperty is not a function 错误,大概率是对象原型被重写或为 null
  • 使用 for...in 遍历时,想过滤掉原型属性,但又不能保证 obj.hasOwnProperty 可用 → 改用 Object.hasOwn(obj, key)
  • 在 TypeScript 中,obj.hasOwnProperty 类型推导常为 any,而 Object.hasOwn 类型更精确((obj: unknown, prop: PropertyKey) => boolean

兼容性与降级方案怎么选

现代环境(Chrome 93+、Firefox 92+、Safari 15.4+、Node.js 16.9+)原生支持 Object.hasOwn。若需兼容旧版运行时,不要手写 polyfill 模拟 hasOwnProperty 行为——那会带回原有缺陷。

  • 推荐用 core-jsObject.hasOwn 特性补丁,它做了健壮性封装(例如对非对象参数返回 false
  • 避免 Object.prototype.hasOwnProperty.call(obj, key) 这类“传统写法”,它仍可能因 Object.prototype 被污染而失败
  • 构建工具(如 Webpack/Vite)开启 target: 'es2022' 后,Babel 默认不转换 Object.hasOwn;若需转译,请确认插件版本 ≥ @babel/plugin-transform-object-has-own v7.22+

实际替换时容易忽略的细节

看似简单的一对一替换,实际有三个关键点常被跳过:

  • 函数签名不同:obj.hasOwnProperty(prop) 是方法调用,Object.hasOwn(obj, prop) 是静态函数调用 —— 注意参数顺序和上下文
  • 箭头函数中不能用 this.hasOwnProperty,但可以安全写 Object.hasOwn(this, 'x')
  • ESLint 规则 no-prototype-builtins 已默认警告 hasOwnProperty,启用后会提示改为 Object.hasOwn,但不会自动修复嵌套调用(如 obj?.hasOwnProperty?.(key)),需人工检查

最易被忽略的是:某些库(如早期版本的 Lodash)内部仍用 hasOwnProperty,升级前要确认其是否已适配 Object.hasOwn;否则即使业务代码全替换了,底层仍可能触发原型污染问题。

相关文章

精彩推荐