应弃用hasownproperty,改用es2022原生object.hasown;它不查原型链、兼容null对象与symbol键,且现代环境已广泛支持,旧环境宜用mdn轻量polyfill而非工具库。

直接用工具库“弥补”hasOwnProperty的局限性,不是最优解——它的根本问题在于设计层面依赖原型链,任何基于它封装的工具方法都绕不开被污染的风险。真正有效的做法是**弃用它,改用语言原生提供的安全替代方案**。
为什么工具库难以真正“弥补”
多数通用工具库(如 Lodash、underscore)提供的 has 或 hasIn 方法,底层仍可能调用 obj.hasOwnProperty 或 prop in obj:
-
仍受原型污染影响:如果
Object.prototype.hasOwnProperty被篡改,Lodash 的has在某些版本里也会失效(尤其未显式绑定原始方法时) -
语义不统一:Lodash
has(obj, 'a.b')支持路径访问,但这是“是否可访问”,不是“是否为自有属性”,和hasOwnProperty的原始意图已偏离 - 引入额外依赖:只为解决一个语言层已有标准解的问题,增加包体积和维护成本
现代环境推荐:用 Object.hasOwn 直接替代
ES2022 原生的 Object.hasOwn(obj, prop) 就是专为解决这些问题而设计的,无需第三方介入:
- 不查原型链,不调用对象任何方法,彻底规避覆盖或缺失风险
- 对
Object.create(null)、冻结对象、自定义hasOwnProperty属性的对象全部兼容 - 支持 Symbol 键,参数类型明确(
obj: object,prop: PropertyKey),TypeScript 类型推导更准 - Chrome 93+、Firefox 92+、Safari 15.4+、Node.js 16.9+ 均已原生支持
旧环境兜底:谨慎使用 polyfill,而非依赖工具库
若必须支持 Node.js
- ✅ 推荐 MDN 官方 polyfill(轻量、只补核心行为):
if (!Object.hasOwn) Object.hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty); - ⚠️ 注意:该 polyfill 仍依赖
Object.prototype.hasOwnProperty未被污染——若系统已遭篡改,说明安全边界已失守,此时更需排查根源,而非仅补检测逻辑 - ❌ 避免用工具库的
_.has等做“等价替换”,它解决的是不同问题,且可能掩盖真实风险
构建与检查:用工具预防,而非 runtime 弥补
真正的弥补发生在开发阶段:
- ESLint 配置
no-prototype-builtins规则,自动拦截obj.hasOwnProperty调用 - CI 中启用 TypeScript +
"lib": ["es2022"],让类型系统提前报错 - Webpack/Vite 构建时设
target: "es2022",避免 Babel 错误降级











