javascript中可通过三种方式动态拦截方法:一是直接替换原型方法,影响所有实例;二是用object.setprototypeof切换单个对象原型;三是用proxy代理对象本身,不改原型链。

JavaScript 中可以通过直接操作对象的原型链,在运行时动态重写或拦截方法。核心思路是:替换原型上的方法引用,或用代理(Proxy)包装目标对象,但要注意原型链修改的时机与作用范围。
直接替换原型上的方法
这是最直接的方式,适用于所有继承该原型的对象(包括已存在和后续创建的实例)。需注意原方法是否需要被调用(如保留原有逻辑),以及是否要绑定正确上下文。
- 获取目标构造函数的 prototype(如
Array.prototype或自定义类的MyClass.prototype) - 保存原始方法(可选),便于在新实现中调用:
const originalPush = Array.prototype.push; - 覆盖方法:
Array.prototype.push = function(...args) { console.log('push called with', args); return originalPush.apply(this, args); }; - 注意:若方法使用了
this内部调用其他原型方法,需确保上下文不丢失(用apply或箭头函数慎用)
用 Object.setPrototypeOf 动态切换实例原型
适用于对单个对象做行为定制,不影响其他实例。通过临时替换其内部 [[Prototype]],实现“运行时换肤”式方法拦截。
- 创建一个新原型对象,包含重写后的方法:
const interceptedProto = { toString() { return '[intercepted]'; } }; - 修改实例原型:
Object.setPrototypeOf(obj, interceptedProto); - 后续调用
obj.toString()就会走新实现;恢复原行为只需再设回原原型(需提前保存) - 限制:不能拦截非自有属性访问以外的底层操作(如
for...in枚举顺序、instanceof判定会变)
用 Proxy 拦截方法调用(不改原型链但效果类似)
Proxy 不修改原型链结构,而是代理对象本身,在访问时动态介入。它比原型替换更灵活、更安全,尤其适合只针对特定对象的拦截。
- 对目标对象包裹一层 Proxy:
const proxied = new Proxy(obj, { get(target, prop) { if (typeof target[prop] === 'function') { return function(...args) { console.log(`calling ${prop}`); return target[prop].apply(target, args); }; } return target[prop]; } }); - 优势:不污染原型、可精确控制每个属性、支持 set/delete/construct 等多种 trap
- 注意:Proxy 返回的是新对象,原对象未变;且无法拦截私有字段(#)或不可配置属性的访问
注意事项与边界情况
动态修改原型链虽强大,但容易引发隐蔽问题,务必谨慎。
- 内置对象(如 Array、Date)的原型修改在严格模式下可能报错,且某些环境(如某些浏览器扩展或框架)会冻结内置原型
- ES6 class 的方法默认不可写、不可配置,直接赋值会静默失败(需先
Object.defineProperty改为可写) - 如果对象已通过
Object.freeze或Object.seal处理,原型无法被修改 - 多个模块同时修改同一原型时,容易相互覆盖,建议封装成可卸载的 patch,并提供 restore 接口
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











