前言 Proxy可以理解成,在目标对象之前架设一层拦截,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy这个词的原意是代理,用在这里表示由它来代理某些操作,可以译为代理器。语法varproxynewProxy(target,handler); Proxy对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中:newProxy()表示生成一个Proxy实例target参数表示所要拦截的目标对象handler参数也是一个对象,用来定制拦截行为 如果handler没有设置任何拦截,那就等同于直接通向原对象。lettarget{};lethandler{};letproxynewProxy(target,handler);proxy。name编程三昧;console。log(target。name);编程三昧 还有一个技巧是将Proxy对象,设置到object。proxy属性,从而在object对象上调用:letproxynewProxy({},{get:function(target,property){return35;}});letobjObject。create(proxy);obj。time35get() get()方法用于拦截某个属性的读取操作,可以接受三个参数,依次为:目标对象属性名proxy实例本身(严格地说,是操作行为所针对的对象),可选。 get()方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子:letperosn{name:james,age:26,profession:software}varproxynewProxy(perosn,{get:function(target,property){if(propertyintarget){returntarget〔property〕;}else{thrownewReferenceError(propertypepropertydoesnoexit);}}});console。log(proxy。name,proxy。profession);jamessoftwareconsole。log(proxy。sex);UncaughtReferenceError:propertypesexdoesnoexitset() set()方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为:目标对象属性名属性值Proxy实例本身,可选。 假定person对象有一个age属性,该属性应该是一个不大于200的整数,那么可以使用Proxy保证age的属性值符合要求。letperosn{name:james,age:26,profession:software}letproxynewProxy(perosn,{get:function(target,property){if(propertyintarget){returntarget〔property〕;}else{thrownewReferenceError(propertypepropertydoesnoexit);}},set:function(target,key,value){if(keyage){if(value80){throwReferenceError(invail);}else{returntarget〔key〕value;}}else{returntarget〔key〕;}}});proxy。age60;console。log(proxy。name,proxy。profession,proxy。age);jamessoftware60proxy。age99;UncaughtReferenceError:invailapply() apply()方法拦截:函数的调用call操作apply操作 apply()方法可以接受三个参数,分别是:目标对象目标对象的上下文对象(this)目标对象的参数数组。lettwice{apply(target,ctx,agrs){returnReflect。apply(。。。arguments)2;}};functionsum(a,b){returnab;}letproxy5newProxy(sum,twice);console。log(proxy5(1,3));8console。log(proxy5。apply(null,〔1,3〕));8 另外,直接调用Reflect。apply方法,也会被拦截。Reflect。apply(proxy5,null,〔9,10〕)38has() has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。 has()方法可以接受两个参数,分别是目标对象、需查询的属性名。 下面的例子使用has方法隐藏某些属性,不被in运算符发现。letstu1{name:张三,score:59};letstu2{name:李四,score:99};lethandler{has(target,prop){if(propscoretarget〔prop〕60){console。log({target。name}不及格);returnfalse;}returnpropintarget;}}letoproxy1newProxy(stu1,handler);letoproxy2newProxy(stu2,handler);scoreinoproxy1张三不及格falsescoreinoproxy2truefor(letainoproxy1){console。log(oproxy1〔a〕);}张三59for(letbinoproxy2){console。log(oproxy2〔b〕);}李四99 上面代码中,has拦截只对in运算符生效,对for。。。in循环不生效,导致不符合要求的属性没有被for。。。in循环所排除。Proxy支持的拦截操作一览 Proxy支持的拦截操作基本有13种。get(target,propKey,receiver) 拦截对象属性的读取,比如:proxy。fooproxy〔foo〕。set(target,propKey,value,receiver) 拦截对象属性的设置,比如proxy。foov或proxy〔foo〕v,返回一个布尔值。has(target,propKey) 拦截propKeyinproxy的操作,返回一个布尔值。deleteProperty(target,propKey) 拦截deleteproxy〔propKey〕的操作,返回一个布尔值。ownKeys(target) 拦截:Object。getOwnPropertyNames(proxy)Object。getOwnPropertySymbols(proxy)Object。keys(proxy)for。。。in循环 以上拦截都返回一个数组。 该方法返回目标对象所有自身的属性的属性名,而Object。keys()的返回结果仅包括目标对象自身的可遍历属性。getOwnPropertyDescriptor(target,propKey) 拦截Object。getOwnPropertyDescriptor(proxy,propKey),返回属性的描述对象。defineProperty(target,propKey,propDesc) 拦截:Object。defineProperty(proxy,propKey,propDesc)Object。defineProperties(proxy,propDescs) 返回一个布尔值。preventExtensions(target) 拦截Object。preventExtensions(proxy),返回一个布尔值。getPrototypeOf(target) 拦截Object。getPrototypeOf(proxy),返回一个对象。isExtensible(target) 拦截Object。isExtensible(proxy),返回一个布尔值。 setPrototypeOf(target,proto) 拦截Object。setPrototypeOf(proxy,proto),返回一个布尔值。 如果目标对象是函数,那么还有两种额外操作可以拦截。 apply(target,object,args) 拦截Proxy实例作为函数调用的操作,比如:proxy(。。。args)proxy。call(object,。。。args)proxy。apply(。。。)。construct(target,args) 拦截Proxy实例作为构造函数调用的操作,比如:newproxy(。。。args)。 本文完,感谢阅读! 学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂! 大家好,我是编程三昧的作者隐逸王,我的公众号是编程三昧,欢迎关注,希望大家多多指教!