receiver 是 proxy handler.get 的第四个参数,用于指定 getter 执行时的 this 值;它不改变属性查找路径,仅确保 reflect.get 或访问器属性中 this 正确指向原始调用对象(如代理实例或子类实例),避免继承场景下上下文错位。

receiver 参数用于指定 Proxy 的 get 操作中,当读取的属性是访问器属性(getter)时,该 getter 内部 this 的指向对象。它不改变属性查找路径,只影响 getter 执行时的上下文。
receiver 是什么:不是目标对象,而是 this 绑定目标
Reflect.get(target, key, receiver) 中的 receiver 与 Proxy 的 handler 中 get 方法的第四个参数同义。它的核心作用是:当 target[key] 是一个 getter 函数时,JavaScript 引擎会以 receiver 作为 this 值来调用该 getter —— 类似于 getter.call(receiver)。
注意:receiver 不影响属性是否能被找到(查找仍从 target 开始,沿原型链进行),只影响 getter 执行时的 this。
为什么需要它:修复继承链中 getter 的 this 错位
在类继承中,若父类定义了 getter,子类实例访问该 getter 时,默认 this 是子类实例(通常符合预期)。但若通过 Reflect.get 或 Proxy 显式读取,且未传 receiver,this 可能意外变成 target(比如父类原型),导致逻辑错误或报错(例如访问子类私有字段失败)。
典型场景:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- Proxy 拦截 get,内部用 Reflect.get 转发,但没传 receiver → getter 内部 this 指向 Proxy 而非原始实例
- 手动实现属性代理或装饰器时,需保持 getter 的语义一致性
怎么用:始终把原始操作对象传给 receiver
正确做法是:只要你在模拟“某个对象访问属性”的行为,就应把那个对象作为 receiver。
- 在 Proxy 的 get handler 中:直接把
receiver(即 handler 的第 4 个参数)透传给 Reflect.get - 独立调用 Reflect.get 时:若你本意是“让 obj.foo 的 getter 以 obj 为 this 运行”,那就写
Reflect.get(obj, 'foo', obj)
示例:
class Parent {
get value() { return this._data ?? 'default'; }
}
class Child extends Parent {
constructor() {
super();
this._data = 'child';
}
}
const child = new Child();
console.log(child.value); // 'child' —— 正常,this 是 child
// ❌ 错误:没传 receiver,this 指向 Parent.prototype
console.log(Reflect.get(Child.prototype, 'value')); // 'default'(因为 this._data 在 Parent.prototype 上为 undefined)
// ✅ 正确:显式指定 receiver 为 child 实例
console.log(Reflect.get(Child.prototype, 'value', child)); // 'child'
和 Proxy 的关联:receiver 是 Proxy 行为一致性的关键
当你创建 Proxy 并拦截 get,必须将 handler 的 receiver 参数传给 Reflect.get,否则 getter 中的 this 会变成 Proxy 实例本身,而非被代理的目标对象(或其子类实例),破坏封装和继承语义。
- Proxy handler 的 get 方法签名:
get(target, key, receiver) - 转发时应写:
Reflect.get(target, key, receiver),而不是Reflect.get(target, key)
漏掉 receiver 是 Proxy 中最常见且隐蔽的 bug 来源之一,尤其涉及 getter、bind、箭头函数或私有字段访问时。










