construct拦截器仅捕获new关键字或Reflect.construct调用,需定义construct(target,args,newTarget)方法并返回对象;不触发于普通函数调用、缺newTarget参数或非构造函数场景。

可以用 construct 拦截器精准捕获所有标准 new 调用,但必须清楚它只响应明确使用 new 关键字或 Reflect.construct 的场景,不覆盖类的普通函数调用或 call/apply 等变通用法。
construct 拦截器的基本写法
handler 必须定义 construct(target, args, newTarget) 方法,其中:
-
target 是被
new调用的原始构造函数(如class A{}) - args 是传给构造函数的参数数组,可直接解构或遍历
-
newTarget 是实际被
new的函数,用于判断是否子类继承调用(target !== newTarget表示子类实例化) - 必须返回一个对象,否则会抛出
TypeError
典型监控埋点逻辑
在 construct 中插入日志、计时、统计或弱引用关联,例如:
- 记录类名、参数个数、是否为子类调用:
console.log('[new]', { class: target.name, argCount: args.length, isSubclass: target !== newTarget }) - 用
WeakMap关联实例与元信息(避免内存泄漏):instanceMap.set(instance, { createdAt: Date.now(), class: target.name }) - 调用
Reflect.construct(target, args, newTarget)完成真实构造,再对返回实例做后处理
必须注意的生效边界
construct 不是“万能拦截”,以下情况完全不触发:
- 类被当作普通函数调用:
MyClass()(无new) - 用
Reflect.construct但未传newTarget参数(即第三个参数缺失) - 目标不是可构造函数(如普通对象、箭头函数),Proxy 会直接报错
- 代理对象本身没被
new,比如只读取属性或调用方法,不会进 construct
实用示例:带统计的类代理
下面代码创建一个可统计实例化次数的代理:
function Counter() { this.id = Math.random(); }
const countMap = new Map();
const handler = {
construct(target, args, newTarget) {
const className = target.name;
countMap.set(className, (countMap.get(className) || 0) + 1);
console.log(`[${className}] 实例化第 ${countMap.get(className)} 次`);
return Reflect.construct(target, args, newTarget);
}
};
const ProxyCounter = new Proxy(Counter, handler);
new ProxyCounter(); // [Counter] 实例化第 1 次
new ProxyCounter(); // [Counter] 实例化第 2 次

















