一、Reflect ES6提供了一个全新的选择APIReflect,Reflect和Proxy是相对的,我们可以用Reflect操作对象。 1。1Reflect存在的意义1)将Object对象一些内部的方法,放到Reflect对象上。比如Object。defineProperty 现阶段这些方法存在于object和Reflect对象上,未来只存在于Reflect对象上。 意义:也就是说,从Reflect对象上可以拿到语言内部的方法。2)操作对象出现报错返回false 比如:Object。defineProperty(obj,name,desc)在无法定义属性时,会抛出一个错误,而Reflect。defineProperty(obj,name,desc)则会返回false,这样会更合理一些。旧写法try{Object。defineProperty(target,property,attributes);}catch(err){failure}新写法if(Reflect。defineProperty(target,property,attributes)){success}else{failure}3)让操作对象的编程变为函数式编程 说明:老写法有的是命令式编程,比如下面这个例子老写法assigninOtrue新写法Reflect。has(Object,assign);true4)保持和Proxy对象的方法一一对应 说明:Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。Proxy(target,{set:function(target,name,value,receiver){varsuccessReflect。set(target,name,value,receiver);if(success){console。log(propertynameontargetsetdovalue);}},}); 这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。 综上所述:Reflect对象有4个意义:从Reflect对象上可以拿到语言内部的方法。操作对象出现报错时返回false让操作对象都变为函数式编程保持和proxy对象的方法一一对应1。2Reflect常用API 静态方法 Reflect一共有13个静态方法 它可以一部分是原来在Object上的方法,将它转移到了Reflect上,并做了小改动,让方法更加合理。Reflect。defineProperty(target,name,desc)与Object。defineProperty(target,name,desc)类似,当时对象无法定义时,Object。defineProperty会报错,而Reflect。defineProperty不会,它会返回false,成功时返回true,如果不是对象还是会报错。Reflect。getPrototypeOf(target)与Object。getPrototypeOf一样,返回指定的对象的原型。Reflect。setProtoTypeOf(target,prototype)和Object。setPrototypeOf(target,prototype)一样,它将指定对象的原型设置为另一个对象。Reflect。getOwnPropertyDescriptor(target,name)和Object。getOwnPropertyDescriptor(target,name)一样,如果在对象中存在,则返回给定的属性的属性描述符。Reflect。isExtensible(target)与Object。isExtensible(target)类似,判断一个对象是否可扩展(是否可以在它上面添加新的属性),它们的不同点是,当参数不是对象时(原始值),Object将它强制转换为一个对象,Reflect直接报错。Reflect。preventExtensions(target)与Object。preventExtensions(target)类似,阻止新属性添加到对象,不同点和上一条一样。Reflect。apply(target,thisArg,args)与Function。prototype。apply。call(fn,obj,args)一样Reflect。ownKeys(target)与Object。getOwnPropertyNames(target)。concat(Object。getOwnPropertySymbols(target))一样,返回一个包含所有自身属性(不包含继承属性)的数组。 另一部分是将原来操作符的功能,变成函数行为Reflect。has(target,name)与in操作符一样,让判断操作都变成函数行为Reflect。deleteProperty(target,name)与delete操作符一样,让删除操作变成函数行为,返回布尔值代表成功或者失败Reflect。construct(target,args〔,newTarget〕)与new操作符一样,target构造函数,第二参数是构造函数的参数类数组,第三参数是new。target的值。Reflect。get(target,name〔,receiver〕)与Obj〔key〕一样,第三个参数是要取值的key部署了getter时,访问其函数的this绑定为receiver对象。Reflect。set(target,name,value〔,receiver〕)设置target对象的key属性等于value,第三个参数和set一样。返回一个布尔值。老写法assigninOtrue新写法Reflect。has(Object,assign);true老写法Function。prototype。apply。call(Math。floor,undefined,〔1。75〕);1新写法Reflect。apply(Math。floor,undefined,〔1。75〕);1旧写法deletemyObj。新写法Reflect。deleteProperty(myObj,foo);new的写法constinstancenewGreeting(张三);Reflect。construct的写法constinstanceReflect。construct(Greeting,〔张三〕);旧写法Object。defineProperty(MyDate,now,{value:()Date。now(),});新写法Reflect。defineProperty(MyDate,now,{value:()Date。now(),});Reflect。get(1,foo);报错Reflect。get(false,foo);报错Reflect。set(1,foo,{});报错Reflect。set(false,foo,{});报错varmyObject{foo:1,bar:2,getbaz(){returnthis。foothis。},};varmyReceiverObject{foo:4,bar:4,};Reflect。get(myObject,baz,myReceiverObject);8 ES6为new命令引入了一个new。target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect。construct()调用的,new。target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。functionPerson(name){if(new。targetPerson){this。}else{thrownewError(必须使用new命令生成实例);}}二、Proxy Proxy对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等),等同于在语言层面做出修改,所以属于一种元编程(metaprogramming),即对编程语言进行编程。 Proxy就像在目标对象之间的一个代理,任何对目标的操作都要经过代理。代理就可以对外界的操作进行过滤和改写。 Proxy是构造函数,它有两个参数target和handler。 target是用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 handler是一个对象,其属性是当执行一个操作时定义代理的行为函数。varobjnewProxy({},{get:function(target,key,receiver){console。log(getting{key});returnReflect。get(target,key,receiver);},set:function(target,key,value,receiver){console。log(setting{key});returnReflect。set(target,key,value,receiver);},});obj。count1;settingcountobj。gettingcountsettingcount2 Proxy只有一个静态方法revocable(target,handler)可以用来创建一个可撤销的代理对象。两个参数和构造函数的相同。它返回一个包含了所生成的代理对象本身以及该代理对象的撤销方法的对象。 一旦某个代理对象被撤销,它将变的几乎完全不可用,在它身上执行任何的可代理操作都会抛出TypeError异常(注意,可代理操作一共有14种,执行这14种操作以外的操作不会抛出异常)。一旦被撤销,这个代理对象永远不可能恢复到原来的状态,同时和它关联的目标对象以及处理器对象将有可能被垃圾回收掉。调用撤销方法多次将不会有任何效果,当然,也不会报错。varrevocableProxy。revocable({},{get(target,name){return〔〔name〕〕;},});revocable{proxy:proxy,revoke:revoke}varproxyrevocable。proxy。〔〔foo〕〕revocable。revoke();执行撤销方法proxy。TypeErrorproxy。foo1;TypeErrordeleteproxy。TypeEobject因为typeof不属于代理操作 handler参数是代理函数对象,它一共支持13种拦截函数。和Reflect的相同。如果没有定义某种操作,那么这种操作会被转发到目标对象身上。constproxynewProxy({},{get:function(target,property,receiver){receiver总是指向原始的读操作所在的那个对象,一般情况下就是Proxy实例。},});proxy。getRtrue 如果一个属性不可配置(configurable)且不可写(writable),则Proxy不能修改该属性,否则通过Proxy对象访问该属性会报错。consttargetObject。defineProperties({},{foo:{value:123,writable:false,configurable:false,},});consthandler{get(target,propKey){},};constproxynewProxy(target,handler);proxy。TypeError:Invariantcheckfailed apply方法拦截函数的调用、call和apply操作。vartargetfunction(){returnI};varhandler{apply:function(){returnI},};varpnewProxy(target,handler);p();Iamtheproxy defineProperty方法拦截了Object。defineProperty操作。varhandler{defineProperty(target,key,descriptor){},};vartarget{};varproxynewProxy(target,handler);proxy。不会生效defineProperty方法返回false,导致添加新属性总是无效。 注意,如果目标对象不可扩展(nonextensible),则defineProperty不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则defineProperty方法不得改变这两个设置。 getPrototypeOf方法主要用来拦截获取对象原型,会拦截以下这些操作:Object。prototype。protoObject。prototype。isPrototypeOf()Object。getPrototypeOf()Reflect。getPrototypeOf()instanceof ownKeys方法用来拦截对象自身属性读取的操作,会拦截以下操作:Object。getOwnPropertyNames()Object。getOwnPropertySymbols()Object。keys()for。。。in 通过代理,你可以轻松地验证向一个对象的传值。letvalidator{set:function(obj,prop,value){if(propage){if(!Number。isInteger(value)){thrownewError(Theageisnotaninteger);}if(value200){thrownewError(Theageseemsinvalid);}}Thedefaultbehaviortostorethevalueobj〔prop〕},};letpersonnewProxy({},validator);person。age100;console。log(person。age);100person。抛出异常:UncaughtTypeError:Theageisnotanintegerperson。age1000;抛出异常:UncaughtRangeError:Theageseemsinvalidthis指向 虽然Proxy可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在Proxy代理的情况下,目标对象内部的this关键字会指向Proxy代理。consttarget{m:function(){console。log(thisproxy);},};consthandler{};constproxynewProxy(target,handler);target。m();falseproxy。m();trueconsttargetnewDate();consthandler{};constproxynewProxy(target,handler);proxy。getDate();TypeError:thisisnotaDateobject。getDate方法只能在Date对象实例上面拿到,如果this不是Date对象实例就会报错。这时,this绑定原始对象,就可以解决这个问题consttargetnewDate(20210728);consthandler{get(target,prop){if(propgetDate){returntarget。getDate。bind(target);}returnReflect。get(target,prop);},};constproxynewProxy(target,handler);proxy。getDate();28