捕获器参数和反射 API

151 阅读2分钟

捕获器参数和反射 API

  • 所有的 捕获器 都可以访问相应的参数,基于这些参数可以重建被捕获方法的原始行为。比如 get()捕获器会接收到 目标对象要查询的属性代理对象 三个参数。

    const target = {
      foo: "bar";
    }
    const handler = {
      // 三个参数依次为,目标对象, 要查询的属性,代理对象
      get(trapTarget, property, receiver) {
        console.log(trapTarget === target);
        console.log(property);
        console.log(receiver === proxy)
      }
    }
    const proxy = new Proxy(target, handler)
    proxy.foo;
    // true;
    // foo;
    // true
    

    有了这些参数就可以重建被捕获方法的原始行为

    const target = {
      foo: "bar",
    };
    const handler = {
      get(trapTarget, property, receiver) {
        return trapTarget[property];
      },
    };
    
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); // bar
    console.log(target.foo); // bar
    
  • 所有的捕获器都可以基于自己的参数重建原始操作,但并非所有捕获器行为都像 get()那么简单。因此,通过手动写码如法炮制的想法是不现实的。实际上,开发者并不需要手动重建原始行为,而是可以通过调用全局的 Reflect 对象上(封装了原始行为)的同名方法来轻松重建。

  • 处理程序对象中所有可以捕获的方法都有对应的反射(Reflect)API 方法。这些方法与捕获器拦截的方法具有相同的名称和函数签名,而且也具有与被拦截方法相同的行为。因此,使用反射 API 也可以像下面这样定义出空代理对象。

    const target = {
      foo:"bar";
    }
    const handler = {
      get() {
        return Reflect.get(...arguments)
      }
    }
    const proxy = new Proxy(target, handler)
    console.log(proxy.foo); // bar;
    console.log(target.foo); // bar
    
  • 甚至还可以写的更简洁一些:

    const target = {
      foo: "bar",
    };
    const handler = {
      get() {
        return Reflect.get();
      },
    };
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); // bar;
    console.log(target.foo); // bar
    
  • 事实上,如果真想创建一个可以捕获所有方法,然后将每个方法转发给对应反射 API 的空代理,那么甚至不需要定义处理程序对象。

    const target = {
      foo: "bar",
    };
    const proxy = new Proxy(target, Reflect);
    console.log(proxy.foo); // bar;
    console.log(target.foo); // bar
    
  • 反射 API 为开发者准备好了样板代码,再此基础上开发者可以用最少的代码修改捕获器的方法,比如,下面的代码在某个属性被访问时,会对返回的值进行一番修饰。

    const target = {
      foo: "bar",
      baz: "qux",
    };
    
    const handler = {
      get(trapTarget, property, receiver) {
        let decoration = "";
        if (property === "foo") {
          decoration = "!!!";
        }
        return Reflect.get(...arguments) + decoration;
      },
    };
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); //bar!!!
    console.log(target.foo); //bar
    
    console.log(proxy.baz); //qux
    console.log(target.baz); //qux