Proxy详解
概述
Proxy可以理解为,在目标对象之前设一层"拦截",外界对该对象的访问,都必须通过这层拦截,可以对外界的访问进行过滤和改写(表示可以用它"代理"某些操作,可以翻为“代理器")。
以上示例中所代理的目标对象是一个空对象,如果没有Proxy的介入,操作原来要访问的就是这个对象,第二个参数是一个配置对象,对于每一个被代理的操作,需提供一个对应的处理函数,该函数拦截对应操作.应为此示例配置对象有一个get方法来拦截对目标对象属性的访问请求.get方法的两个参数(target:目标对象,propKey:所访问的属性),可以看到访问此对象由于get没有设置访问属性统一返回35,所以访问任何属性都得到35。
以上示例由于handler是一个空对象,没有任何拦截,所以访问proxy就等同于访问target。
以上示例表示Proxy也可以作为其他对象的原型,由于proxy对象是obj对象的原型,obj对象本身并没有time属性,所以会根据原型链,会在proxy对象上读取该属性,导致被拦截.
以上示例表示同一个拦截器,可以设置多个拦截操作。
Proxy拦截操作(13种)
1.get(target[被代理的对象],propKey[属性名],receiver[proxy实例本身]):拦截对象属性的读取,比如proxy.foo或proxy['foo']。
2.set(target[被代理的对象],propKey[属性名],value[新的属性值],receiver[proxy实例本身]):拦截对象属性的设置,比如proxy.foo=v或者proxy["foo"]=v,返回一个布尔值。
3.has(target[被代理的对象],propKey[属性名]):拦截propKey in proxy操作,返回一个布尔值
4.deleteProperty(target[被代理的对象],propKey[属性名]):拦截 delete proxy[propKey]操作,返回一个布尔值.
5.ownKeys(target[被代理的对象]):拦截object.getOwnPropertyNames(proxy),Object.getOwnPropertySymbols(proxy),Object.keys(proxy),for...in循环,返回一个数组。该方法,而object.keys()的返回结果仅包括目标对象资深可遍历的属性。
6.getOwnPropertyDescriptor(target[被代理的对象],propKey[属名]):Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
7.defineProperty(target[被代理的对象],propKey[属性名], propDesc[描述符]):拦截Object.defineProperty(proxy,propKey,propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
8.preventExtensions(target[被代理的对象]):拦截Object.preventExtensions(proxy),返回一个布尔值。
9.getPrototypeOf(target[被代理的对象]):拦截Object.getPrototypeOf(proxy),返回一个对象。
10.isExtensible(target[被代理的对象]):拦截Object.isExtensible(proxy),返回一个布尔值。
11.setPrototypeOf(target[被代理的对象], proto[原型对象]):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
12.apply(target[被代理的对象], object[对象this指向], args[参数]):拦截Proxy实例作为函数调用的操作,例如:proxy(...args),proxy.call(object,...args),proxy.apply()。
13.construct(arget[被代理的对象],args[参数]):拦截Proxy实例作为构造函数调用的操作,比如new proxy(...args)。
使用场景示例:
1.利用proxy,可以将读取属性的操作(get),转变为某个函数,从而实现链式操作。
2.实现私有变量
3.简单校验
Proxy.revocable()创建一个可撤销的Proxy对象.该对象的proxy属性是Proxy的实例,revoke属性是一个函数.当revoke函数执行后,在访问Proxy实例,就会报错.