捕获器参数和反射 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