应优先使用 object.getprototypeof() 替代 __proto__,因其读取内部[[prototype]]且不可被覆盖;类型判断用 object.prototype.tostring.call() 而非 instanceof;可冻结内置原型增强防御。

预防对象原型被修改导致检测失效,关键在于避开依赖可变原型链的动态检查方式,转而使用更稳定、不可篡改或直接读取内部结构的方法。
优先用 Object.getPrototypeOf() 替代 __proto__
__proto__ 是可写、可配置的访问器属性,容易被覆盖或删除;而 Object.getPrototypeOf() 是标准方法,读取的是对象内部 [[Prototype]] 的真实值,不受外部赋值干扰。
- ✅ 安全:即使有人执行
obj.__proto__ = null,Object.getPrototypeOf(obj)仍返回原始原型(除非用Object.setPrototypeOf()主动改) - ❌ 避免:
obj.__proto__可被重定义,比如Object.defineProperty(obj, '__proto__', { value: {} })会破坏原有链
检测时绕过原型链,直查构造或类型标识
当目标是判断对象“本质类型”(如是否为数组、Promise、Date),不要依赖 instanceof 或 isPrototypeOf() —— 它们都走原型链,易被污染。
- ✅ 推荐:
Object.prototype.toString.call(obj)返回[object Array]等固定字符串,基于内部 [[Class]] 标识,无法被原型修改影响 - ✅ 补充:对原生构造函数,可比对
obj.constructor === Array,但需注意constructor属性本身也可能被改,所以仅作辅助
冻结关键原型对象(防御性加固)
如果你控制环境(如框架、SDK 初始化阶段),可提前锁定核心原型,防止后续篡改。
- ✅ 冻结内置原型:
Object.freeze(Object.prototype)、Object.freeze(Array.prototype)等,使属性不可增删改(注意:IE 不支持,现代环境可用) - ✅ 创建防篡改对象:
Object.create(Object.freeze({ a: 1 })),确保子对象的原型基础不可变 - ⚠️ 注意:冻结后无法再向该原型添加方法,需在冻结前完成所有扩展
避免 instance 和 isPrototypeOf 在敏感场景单点依赖
这两个方法都依赖原型链完整可达。一旦中间某层被设为 null(如 Object.setPrototypeOf(obj, null))或替换为非标准对象,检测即失效。
- ✅ 替代方案:组合使用
Object.getPrototypeOf()+Object.is()逐级比对关键原型引用,而非只靠布尔结果 - ✅ 对跨 iframe 或沙箱环境,统一用
toString.call()做类型锚定,不信任任何跨上下文的构造函数或 prototype 引用











