Proxy 无法拦截普通对象的 constructor 调用,但可通过代理构造函数本身并使用 construct 捕获器拦截 new 操作;construct 专用于拦截 new 调用,目标必须是可构造函数,且需用 Reflect.construct 保证原型链正确。

JavaScript 中无法用 Proxy 拦截 constructor 调用本身,因为 Proxy 只能代理**对象的属性访问、赋值、函数调用等操作**,而 new Target() 是对**构造函数(即函数对象)本身**的调用,属于“函数调用”行为,不是对某个对象属性的操作。
但你可以通过代理**构造函数本身**(即一个函数对象),并利用 apply 或 construct 捕获器,来拦截 new 行为。关键点在于:要拦截 new Foo(),必须把 Foo 本身包装成一个 Proxy,且该 Proxy 的目标是一个函数,并使用 construct 捕获器。
✅ 正确方式:用 construct 捕获器拦截 new 调用
construct 是专为拦截 new 操作设计的捕获器,仅当代理目标是函数且被 new 调用时触发。
- 目标(target)必须是可构造的函数(普通函数或 class)
- 必须用
construct(target, args, newTarget)捕获器,不能用apply -
apply拦截的是函数调用(如Foo()),construct拦截的是构造调用(如new Foo())
示例:
立即学习“Java免费学习笔记(深入)”;
function Person(name) {
this.name = name;
}
<p>const ProxyPerson = new Proxy(Person, {
construct(target, args, newTarget) {
console.log('new 被拦截了!', args); // ['Alice']
const instance = Reflect.construct(target, args, newTarget);
instance.createdAt = Date.now();
return instance;
}
});</p><p>const p = new ProxyPerson('Alice');
console.log(p.name); // 'Alice'
console.log(p.createdAt); // 时间戳
❌ 常见误区:试图代理实例对象来拦截 constructor
下面这种写法无效:
const obj = { constructor: function() {} };
const proxied = new Proxy(obj, { /* ... */ }); // 这里 proxy 的是 obj,不是构造函数
new proxied.constructor(); // 实际调用的是原函数,proxy 完全不参与
原因:你代理的是普通对象 obj,而 new obj.constructor() 中的 obj.constructor 是一个函数引用,new 直接调用它——Proxy 对该函数调用无感知,除非这个函数本身也是个 Proxy。
⚠️ 注意 constructor 属性本身不可被 construct 捕获
对象上的 constructor 属性(如 {}.constructor)只是个只读引用,修改它不会影响 new 行为;且 Proxy 无法让 new obj.constructor() 进入 construct,因为此时 obj.constructor 是一个裸函数,未被代理。
- 若想控制
obj.constructor的行为,需确保该属性指向一个已被Proxy包装过的函数 - 例如:
obj.constructor = ProxyPerson;,之后new obj.constructor()才会触发construct
? 实用场景建议
- 实现构造过程日志、参数校验、自动注入依赖、返回缓存实例(类似单例包装)
- 配合
newTarget参数可区分是否被继承调用(用于子类构造逻辑定制) - 避免在
construct中直接return {}—— 应优先用Reflect.construct保证原型链正确


















