返回
创建于
状态
公开

在 JavaScript 的 Proxy 拦截器(handler)中,receiver 是一个经常被忽视但至关重要的参数。简单来说,receiver 代表的是“最初接收操作的对象”


核心定义

get(target, property, receiver)set(target, property, value, receiver) 中:

  • target: 被代理的目标对象。
  • property: 想要访问或设置的属性名。
  • receiver:
    • 通常情况下,它就是 Proxy 实例本身
    • 如果 Proxy 被作为另一个对象的原型(prototype),那么 receiver 指向的是那个继承自 Proxy 的对象

为什么需要 receiver?

receiver 的存在主要是为了正确处理原型链继承中的 this 绑定问题。

如果不使用 receiver,当访问目标对象(target)中的 getter 时,getter 内部的 this 将指向 target。如果使用了 Reflect.get(target, property, receiver),则可以将 this 正确绑定到 receiver 上。

场景演示:继承中的 this 偏移

javascript
1const parent = {
2  name: 'Parent',
3  get fullName() {
4    return this.name;
5  }
6};
7
8const handler = {
9  get(target, prop, receiver) {
10    console.log('触发 GET:', prop);
11    // 情况 A: 不传 receiver (默认返回 target[prop])
12    // return target[prop]; 
13
14    // 情况 B: 使用 Reflect 并传入 receiver
15    return Reflect.get(target, prop, receiver);
16  }
17};
18
19const proxy = new Proxy(parent, handler);
20
21const child = {
22  name: 'Child'
23};
24
25// 让 child 继承自 proxy
26Object.setPrototypeOf(child, proxy);
27
28console.log(child.fullName);

深度解析:

  1. 当我们调用 child.fullName 时,child 本身没有这个属性,于是去原型链上找。
  2. 原型是 proxy,触发了 handler.get
  3. 此时:
    • targetparent
    • receiverchild(因为是 child 发起的调用)。
  4. 如果不用 receiverReflect.get(target, prop) 会导致 fullName 内部的 this 指向 parent,结果输出 "Parent"。
  5. 如果使用 receiverReflect.get(target, prop, receiver) 会把 this 强制绑定为 child,结果输出 "Child"。

get 与 set 中的具体表现

拦截器receiver 的典型值作用
get发起读取操作的对象确保 getter 函数内部的 this 指向调用者,而非目标原对象。
set发起赋值操作的对象确保 setter 函数内部的 this 指向调用者,防止在继承关系中赋值错位。

Set 中的注意事项

set 拦截器中,如果你使用 Reflect.set(target, prop, value, receiver),它会触发 receiver 上的 setter(如果有的话),或者直接在 receiver 对象上定义属性,而不是修改 target。这符合原生 JavaScript 的赋值行为:赋值操作通常发生在当前对象上,而不是原型上。


最佳实践

在编写 Proxy 时,为了保证代码的健壮性(特别是考虑到将来可能被继承的情况),始终建议配合 Reflect 使用 receiver

javascript
1const handler = {
2  get(target, prop, receiver) {
3    // 逻辑处理...
4    return Reflect.get(target, prop, receiver);
5  },
6  set(target, prop, value, receiver) {
7    // 逻辑处理...
8    return Reflect.set(target, prop, value, receiver);
9  }
10};