当前位置: 首页 > Web前端 > JavaScript

[js]代理与反射(Proxy-Reflect)

时间:2023-03-27 01:46:39 JavaScript

ProxyProxy用于为对象创建代理,实现基本操作的拦截和自定义,过滤和重写外部访问constp=newProxy(target,handler)target:要拦截的目标对象handler:要拦截的行为示例consto={a:1,b:2}constp=newProxy(o,{get(target,key,receiver){console.log(`getting${key}!`);returntarget[key]}})console.log(p.a);设置一个!1对象o属性读取的拦截目标可以是空对象,那么拦截操作会直接作用于Proxy实例化对象1handler拦截操作get()set()has()deleteProperty()ownKeys()getOwnPropertyDescriptor()defineProperty()apply()getPrototypeOf()setPrototypeOf()construct()isExtensible()preventExtensions()1.1get(target,key,receiver)拦截读取操作target:目标对象key:读取的属性名receiver:Proxyoranobject继承Proxyconstp=newProxy({},{get(target,key,receiver){console.log(key);console.log(target);console.log(receiver);returntarget[key]}})p.a=2console.log(p.a);1.2set(target,key,value,receiver)拦截赋值操作value:要赋给属性的值constp=newProxy({},{set(target,key,value,接收器){console.log(value);target[key]=值},})p.a=2console.log(p.a);22可以判断设定值,然后决定是否进行赋值操作。当数据发生变化时,可以自动更新DOM,实现数据绑定1.3apply(target,object,args)拦截函数调用,call方法,apply方法target:目标对象(函数)object:调用时的上下文对象args:参数数组当调用functionsum(num1,num2){returnnum1+num2}constp=newProxy(sum,{apply(target,obj,args){console.log(obj);returntarget(...args)}})console.log(p(2,3));p.apply(null,[2,3])undefined5null1.4has(target,key)interceptinoperation返回布尔值consto={_prop:"privateproperty",prop:"foo"}constp=newProxy(o,{has(target,key){if(key.startsWith("_")){returnfalse}returnkeyintarget}})控制台。log("_prop"inp);//falseconsole.log("prop"inp);//true对于不可配置的属性,has拦截会报错for...in循环可以访问has1.5construct(target,args)拦截新操作并返回的属性对象函数Student(name,age){this.名字=名字;this.age=age}constp=newProxy(Student,{construct(target,args){console.log("newoperation");returnnewtarget(...args)}})constp1=newp("张三",18)console.log(p1);'新建操作'{name:"张三",age:18}1.6deleteProperty(target,key)拦截删除操作returnbooleanconsto={_prop:"私有财产",prop:"foo"}constp=newProxy(o,{deleteProperty(target,key){if(key.startsWith("_")){returnfalse}returndeletetarget[key]}})console.log(deletep._prop);//falseconsole.log(deletep.prop);//true拦截不可配置的属性会报错1.7defineProperty(target,key,descriptor)拦截Object.defineProperty(),返回布尔值constp=newProxy({},{defineProperty(target,key,descriptor){target[key]=descriptor.valuereturntrue}})Object.defineProperty(p,'b',{value:"0"})console.log(p.b);//当“0”对象不可扩展时,不能添加目标对象不存在的属性。不能写也不能配置,这两个设置不能拦截和修改1.8getOwnPropertyDescriptor(target,key)拦截Object.getOwnPropertyDescriptor(),返回属性描述对象或undefinedconsto={_prop:"privateproperty",prop:"foo"}constp=newProxy(o,{getOwnPropertyDescriptor(target,key){if(key.startsWith("_")){返回未定义}返回Object.getOwnPropertyDescriptor(target,key)}})console.log(Object.getOwnPropertyDescriptor(p,"_prop"));console.log(Object.getOwnPropertyDescriptor(p,"prop"));undefined{value:"foo",writable:true,enumerable:true,configurable:true}1.9getProptypeOf(target)拦截获取对象原型的操作,返回一个对象相关的操作Object.prototype.__proto__Object.prototype.isPrototypeOf()Object.getPrototypeOf()Object.getPrototypeOf()Reflect.getPrototypeOf()instanceofffunctionStudent(name){this.name=name}conststd=newStudent("张三")letn=1constp=newProxy(std,{getPrototypeOf(target){console.log(`拦截获取原型${n++}`的操作);returnObject.getPrototypeOf(target)}})console.log(Object.getPrototypeOf(p)===Student.prototype);console.log(pinstanceofStudent);console.log(Student.prototype.isPrototypeOf(p));'拦截获取原型1的操作'true'拦截the获取原型的操作2'true'拦截获取原型的操作3'true1.10setPrototypeOf(target,proto)InterceptObject.setPrototypeOf(),returnbooleanfunctionStudent(name){this.name=name}conststd=newStudent("张三")constp=newProxy(std,{setPrototypeOf(target,proto){console.log(`拦截设置原型的操作`);returnObject.setPrototypeOf(target,proto)}})Object.setPrototypeOf(p,Object.create(null))console.log(Object.getPrototypeOf(p));'拦截设置原型的操作'{}非扩展对象不能修改原型1.11ownKeys(target)拦截属性名的读取操作,返回一个数组相关操作Object.getOwnPropertyNames()Object.getOwnPropertySymbols()对象。keys()letfoo=Symbol("foo")consto={a:1,[foo]:"foo"}Object.defineProperty(o,"b",{value:"bar",enumerable:false})让n=1;constp=newProxy(o,{ownKeys(target){console.log(`拦截读取属性名操作${n++}`);returnReflect.ownKeys(target)}})console.log(Object.keys(p));console.log(Object.getOwnPropertyNames(p));console.log(Object.getOwnPropertySymbols(p));'拦截读属性名操作1'['a']'拦截读属性名操作2'['a','b']'拦截读属性名操作3'[Symbol(foo)]1.12isExtensible(target)拦截对象可扩展性判断操作,返回一个布尔值相关操作Object.isExtensible()Object.isFrozen()Object.isSealed()consto={a:1}Object.seal(o)constp=newProxy(o,{isExtensible(target){console.log("Intercept");returnObject.isExtensible(target)}})console.log(Object.isExtensible(p));console.log(Object.isFrozen(p));console.log(Object.isSealed(p));'拦截'false'拦截'false'拦截'true1.13preventExtensions(target)拦截修改对象扩展性的操作,返回一个布尔值相关操作Object.preventExtensions()Object.seal()Object.freeze()consto1={a:1}consto2={b:2}constp=newProxy(o2,{preventExtensions(target){console.log("拦截");if(target===o1){returnfalse}returnObject.preventExtensions(target)}})Object.preventExtensions(p)Object.seal(p)Object.freeze(p)console.log(Object.isExtensible(p));拦截拦截拦截false2Proxy上的方法和属性Proxy.revocable(target,handler)返回一个可撤销的Proxy实例const{proxy,revoke}=Proxy.revocable(target,handler)代理:insProxyrevoke的tance:取消代理的方法consto={a:1}const{proxy:p,revoke}=Proxy.revocable(o,{})console.log(p.a);//1revoke()console.log(p.a);//TypeError:Revoked使用场景:目标对象必须通过代理访问,访问结束后代理权被撤销,是不允许再次访问Reflect内置对象,拦截操作,不是函数对象,不能构造。所有的属性和方法都是静态的,类似于Math对象的静态方法和Proxy的handler中的操作。它与Object上的方法基本相同,只有细微的差别。Reflect的静态方法get(target,name,receiver)set(target,name,value,receiver)has(obj,name)deleteProperty(obj,name)construct(target,args)getPrototypeOf(obj)setPrototypeOf(obj,proto)apply(func,thisArg,atgs)defineProperty(target,key,attr)getOwnPropertyDescriptor(target,key)isExtensible(target)preventExtensions(target)ownKeys(target)1getsetObjectconsto={a:1没有这两个方法,getb(){returnthis.foo},setb(val){returnthis.foo=val}}constb={foo:2}console.log(Reflect.set(o,'a',"1"));//trueconsole.log(Reflect.get(o,'a'));//"1"console.log(Reflect.set(o,'b',"2",b));//trueconsole.log(Reflect.get(o,'b',b));//"2"为属性部署get和set方法,需要指定绑定对象receiver2hasReflect.has(obj,name)相当于obj3中的namedeletePropertyReflect.deleteProperty(obj,name)等同于deleteobj[name]4constructReflect.construct(target,args)等同于newtarget(...args)5getPrototypeOfsetPrototypeOfReflect.getPrototypeOf(obj)等同于Objcet.getPrototype(obj)前者第一个参数不是对象直接报错,后者在运行Reflect.setPrototypeOf(obj,proto)之前会转化为对象,等同于Objcet.setPrototypeOf(obj,proto)。前者第一个参数不是对象直接报错,后者返回参数第一个参数本身是undefined或者null,都报错6applyReflect.apply(func,thisArg,args)相当于Function.prototype.apply.call(func,thisArg,args)等同于func.apply(thisArg,args)是在绑定Fucntion.prototype.apply到func之前,thisArg,args作为apply的参数会被立即调用调用绑定后,相当于func.call(thisArgs,args)7definePropertygetOwnPropertyDescriptorReflect.definProperty(target,key,attr)相当于Object.defineProperty(target,key,descriptor)前者的第一个参数不是一个对象,直接报错Refclt.getOwnPropertyDescriptor(target,key)等价于Object.getOwnPropertyDescriptor(target,key)前者的第一个参数不是对象,后者返回undefined8isExtensiblepreventExtensionsReflect.isExtensible(target)相当于Objcet.isExtensible(target)非对象,前者返回错误,后者返回falseReflect.preventExtensions(target)相当于Objcet.prevetExtensions(target)非对象,前者报错,后者返回原参数9ownKeysReflect.ownKeys(target)返回对象的所有属性相当于Objcet.getOwnPropertyNames(target)和Objcet.getOwnPropertySymbols(target)集合