Web编程技术营地
研究、演示、创新

Proxy

撰写时间:2024-11-05

修订时间:2024-11-05

拦截函数的调用

Proxy可为特定对象创建一个代理,并对其进行相应的拦截。

这个被代理的特定对象可以是一个函数,也可以是对象。如果被代理对象是函数,我们可以使用Proxyapply方法对其拦截。但如果被代理对象是一个对象,而我们希望拦截其特定的一个方法,此时不能使用Proxyapply方法进行拦截,因为我们先使用了诸如obj.greet的方式(尽管其是一个方法),将导致调用Proxyget方法进行拦截。该方法主要是为拦截对象的属性而设立,要在其方法内拦截对象的方法,有点费劲(参见本站Canvas 2D概述使用Proxy技术一节中的源代码)。

鉴于此,我们还是希望调用Proxyapply方法来进行拦截。这需要一些额外的技巧。

现在,设有一对象:

let obj = { greet: function(...msgs) { console.log(msgs); } };

这里只是简单地打印msg参数的信息。注意,此参数为可变长参数,因为console接受可变长参数。因此在这里使用可变长参数直白而合理。

接着,我们创建一个代理,只对obj.greet方法进行拦截。

const handler = { apply: function(target, thisArg, argsArray) { console.log('The proxy is working...'); let newArray = argsArray.map(arg => { return arg + ' (Intercepted)'; }); return target(...newArray); } }; let ObjGreetProxy = new Proxy(obj.greet, handler);

要点一apply方法的argsArray参数不是一个可变长参数,而是一个数组。因此,在我们进行拦截后,我们需要使用...newArray的方式,将数组转换为与objgreet方法相对应的可变长参数。

要点二,使用Arraymap方法来遍历并修改参数值,但该方法不会修改原来的数组,只是返回一个新的数组(详见map语法参考),因此我们在这里必须返回新的数组而不是原数组。

要点三,使用new Proxy(obj.greet, handler)的形式,代理对象不会拦截obj.greet,但会拦截obj.greet()

最后,进行调用:

obj.greet('a', 'b'); // ["a", "b"] (2) ObjGreetProxy('a', 'b'); // ["a (Intercepted)", "b (Intercepted)"] (2)

要点四,不能使用普通的proxy.greet()方式,因为这里代理对象为obj.greet,在其下面并没有greet方法。因此更好的变量名应为ObjGreetFuncProxy,但有点嫌长。

运行Demo

参考资源

  1. Python.org