proxy 的 construct 拦截器专用于劫持 new 表达式调用,是唯一能拦截类实例化过程的原生机制,不修改原始类定义、无侵入,接收 target、args、newtarget 三参数,必须返回 target.prototype 原型的对象,推荐用 reflect.construct 实现并增强实例。

Proxy 的 construct 拦截器专用于劫持 new 表达式调用,是唯一能拦截类实例化过程的原生机制。 它不修改原始类定义,也不要求继承或装饰器,真正实现“无侵入”——只要把类包装进代理,后续所有 new MyClass() 都会经过你的逻辑。
construct 拦截的核心参数与执行流程
当使用 new proxy(...args) 时,construct trap 被触发,接收三个参数:
- target:被代理的原始构造函数(即类本身)
-
args:传给
new的实参数组,如new Cls(1, 'a')→[1, 'a'] -
newTarget:实际被
new的构造器(通常等于proxy,但在继承链中可能不同,用于正确设置this.constructor)
必须返回一个对象,且该对象的 [[Prototype]] 必须是 target.prototype,否则会抛出 TypeError。推荐统一用 Reflect.construct(target, args, newTarget) 返回,它自动处理原型链和 this 绑定。
注入初始化逻辑:在实例创建后、返回前执行
最常见的需求是在新实例生成后自动添加日志、打标记、绑定事件或执行校验。关键点是:不能在 construct 中直接修改 target,而应操作 Reflect.construct 返回的实例:
- 先调用
Reflect.construct创建原始实例 - 对返回的实例做增强(如挂载元信息、调用钩子方法)
- 确保返回的是该实例,而非新对象(否则破坏原型链)
示例:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
const handler = {
construct(target, args, newTarget) {
console.log(`即将 new ${target.name},参数:`, args);
const instance = Reflect.construct(target, args, newTarget);
instance.__createdAt = Date.now(); // 注入元字段
instance.init?.(); // 若存在 init 方法则调用
return instance;
}
};
const ProxyClass = new Proxy(OriginalClass, handler);
const obj = new ProxyClass('test'); // 日志输出 + obj.__createdAt 存在 + obj.init() 被调用
拦截并重写构造行为:支持动态类适配与降级
construct 不仅能“增强”,还能完全接管实例化过程。比如根据环境跳过某些类、替换为 mock 实例、或对参数做预处理:
- 返回自定义对象(需手动设置原型:
Object.setPrototypeOf(obj, target.prototype)) - 根据
args决定是否调用原构造器,或返回缓存实例 - 对参数标准化(如将字符串 ID 自动转为 number)
注意:若返回非 target 原型的对象,必须显式设置原型,否则 instanceof 会失效。
典型限制与避坑要点
construct 拦截有几条硬性约束,忽略会导致静默失败或报错:
- 目标
target必须是函数(包括 class),不能是普通对象或箭头函数 - handler 中未定义
construct时,new 代理会直接失败(TypeError: function is not a constructor) - 不能在
construct中 return 基本类型(string/number/undefined 等),只能返回对象 - 若类内部用了
new.target,代理后new.target是proxy而非原始类,需在 handler 中通过newTarget参数还原语义
本质上,construct 是唯一能从语言层面切入 new 过程的钩子,比装饰器或工厂函数更底层、更透明,也更可控。










