Object.hasOwn专检对象自有属性,不查原型链,而in操作符会遍历整个原型链;原型污染时,前者仍准确返回false,后者可能误判为true,故安全场景必须用Object.hasOwn替代。

直接用 Object.hasOwn 替代所有 obj.hasOwnProperty 和模糊的 key in obj 判断,是解决原型链篡改引发冲突的核心手段。关键不在“选哪个”,而在“停用不安全的旧方式”。
为什么 hasOwn 和 in 会“冲突”
这不是设计缺陷,而是职责根本不同:
-
Object.hasOwn(obj, 'x')只回答:这个对象自己身上有没有叫x的键(不管值是什么,也不管原型上有没有) -
'x' in obj回答的是:从obj开始,顺着整个原型链往上找,能不能访问到x这个名字(哪怕它在Object.prototype上)
当原型被污染(比如 Object.prototype.admin = true),'admin' in someObj 就会意外返回 true;而 Object.hasOwn(someObj, 'admin') 仍严格返回 false——这种“不一致”恰恰是安全机制在起作用,不是 bug。
哪些地方必须立刻切换成 Object.hasOwn
以下场景一旦原型被改写,就可能绕过校验、误读配置或反序列化失败:
- 权限字段检查:如
if (Object.hasOwn(user, 'isSuperAdmin')) { ... } - 配置对象白名单过滤:
Object.keys(config).filter(key => Object.hasOwn(allowedKeys, key)) - JSON 序列化前的字段存在性断言:
if (!Object.hasOwn(data, 'id')) throw new Error('missing id') - 框架 props 或 options 解析时判断用户是否显式传入某选项
如何安全降级兼容老环境
Node.js ≥16.9 / Chrome 93+ / Firefox 92+ / Safari 15.4+ 原生支持 Object.hasOwn。旧环境请用此 polyfill:
注意三点:
-
Object(obj)确保null、undefined不报错,转为空对象再查 - 绝不写
obj?.hasOwnProperty?.(key)——原型已被设为null时仍抛TypeError - 不用
{}.hasOwnProperty.call(...),因为空对象的原型也可能被污染
别再依赖 in 操作符做业务逻辑判断
in 天然不可控,它反映的是“能否访问”,不是“是否配置”。例如:
-
'toString' in {}永远为true(来自Object.prototype) - 攻击者执行
Object.prototype.hidden = 'secret'后,'hidden' in anyPlainObject全部变true
除非你明确需要检测继承属性(极少见),否则所有“这个对象有没有这个字段”的语义,都该由 Object.hasOwn 承担。

















