Proxy中Reflect产生堆栈溢出的根本原因
在Proxy中使用Reflect时,如果不注意很容易产生递归调用堆栈溢出的问题
如何触发
receiver重新出发Proxy的get捕获器的核心机制,设计JavaScript的属性访问规范和Reflect.get的底层行为
1. receiver 的本质 : [[Get]] 的调用者
在JavaScript中,每次属性访问 ( 如: obj.x ) 实际调用的是内部的 [[Get]] 方法
obj.x
→ 引擎调用 `obj.[[Get]]("x", obj)` [[Get]] 是对象的内部抽象操作 , 并非直接暴露的API
const obj = { a: 1 }
// 当执行 obj.a 时:
1. 引擎调用 obj.[[Get]]("x", obj)
2. 检查对象自身属性 → 找到则返回
3. 未找到则遍历原型链 (递归调用[[Get]])
4. 最终未找到则返回undefined
这里的第二个参数就receiver 既谁在访问属性
2.Reflect.get(...) 的工作流程
Reflect.get 并不是简单的返target[prop] , 而是
检查
target是否有getter如果
target有getter,则用receiver作为this执行!如果
target本事是一个Proxy,则重新进入他的捕获器
这里,第二条就是触发递归的原因
如何避免
直接访问目标属性
const handler = {
get(target, prop) {
return target[prop]; // 绕过 [[Get]],直接拿值
}
};安全使Reflect.get
const handler = {
get(target, prop, receiver) {
// 检查是否访问了危险属性(如 getter)
if (prop === 'age') return 42;
return Reflect.get(target, prop); // 不传 receiver
}
};
// 不传 receiver , getter 的 this 默认是target怎么选择
区别对比
代码示例
纯数据代理 ( 无 getter / 继承 )
const safeProxy = new Proxy(data, {
get(target, prop) {
return target[prop]; // 最快最安全的选择
}
});需要保留 getter 的 this ( 如 Vue3 的响应式 )
const reactiveProxy = new Proxy(obj, {
get(target, prop, receiver) {
track(target, prop); // 依赖收集
// 正确传递 receiver 以保证 computed/getter 正常工作
return Reflect.get(target, prop, receiver);
}
});安全兜底方案
const smartProxy = new Proxy(obj, {
get(target, prop, receiver) {
// 如果是特殊属性(如 Symbol 或内部方法)
if (prop === Symbol.iterator) return target[prop];
// 检查是否有 getter
const desc = Object.getOwnPropertyDescriptor(target, prop);
return desc?.get
? Reflect.get(target, prop, receiver) // 保留 this
: target[prop]; // 直接访问
}
});
Proxy中Reflect产生堆栈溢出的根本原因
https://halo.jiangling.site/archives/proxy-handler-reflect