应优先使用object.hasown()检测自有属性,用object.prototype.tostring.call()判断本质类型,创建无原型对象object.create(null)防污染,并结合可选链与类型校验安全调用方法。

关键在于区分“属性是否存在”和“属性是否属于对象自身”,并避开所有依赖原型链的动态检查方式。现代 JavaScript 提供了语义明确、不可被污染的标准方法,只需按需选用即可。
只查自有属性:用 Object.hasOwn()
这是最常用也最安全的方案。它直接检测对象自身是否定义了该属性,完全无视原型链,也不受 hasOwnProperty 被覆盖的影响。
- ✅ 推荐写法:
Object.hasOwn(obj, 'key')(ES2022+) - ✅ 兼容旧环境:
Object.prototype.hasOwnProperty.call(obj, 'key') - ❌ 避免:
obj.hasOwnProperty('key')——若对象自身有同名属性或方法,会失效 - ❌ 不要用:
Object.keys(obj).includes('key')——漏掉不可枚举属性,且性能差
避免原型链干扰的类型判断
当需要确认对象“本质类型”(如是否为数组、日期、正则等),不能靠 instanceof 或 obj.constructor === Array,它们都依赖可被篡改的原型链。
- ✅ 统一用:
Object.prototype.toString.call(obj),返回[object Array]这类固定字符串,基于内部[[Class]]标识,无法伪造 - ✅ 对原生构造器,可辅以
Object.getPrototypeOf(obj) === Array.prototype,比对原型引用本身,不走查找逻辑 - ❌ 慎用:
obj instanceof Array——跨 iframe 时失败;obj.__proto__ === Array.prototype——__proto__可被重定义
创建无原型对象,从源头切断污染
如果对象仅作键值容器使用(如配置项、映射表、缓存),根本不需要继承 Object.prototype 上的方法,那就直接不用它。
- ✅ 创建时用:
const map = Object.create(null),得到的对象原型为null,天然免疫原型污染 - ✅ 注意:它没有
toString、hasOwnProperty等方法,需显式调用:Object.prototype.hasOwnProperty.call(map, key) - ✅ 适合场景:路由参数解析、插件注册表、临时数据聚合等纯字典用途
- ❌ 不要用于需要
instanceof Object判断的逻辑——这类判断本就不该用于数据容器
调用方法前做双重校验
防止因原型被污染导致误调用或静默失败,尤其在处理第三方或用户输入对象时。
- ✅ 用可选链:
obj.handler?.(arg),避免TypeError: Cannot read property 'xxx' of undefined - ✅ 类型校验:
typeof obj.method === 'function',比obj.method != null更精准,不触发 getter - ✅ 自有性校验:
Object.hasOwn(obj, 'method') && typeof obj.method === 'function',确保是对象自己定义的函数 - ❌ 避免:
if (obj.method) { obj.method() }——假值(0、false、'')会跳过,且可能误调原型上的同名属性











