关注前端,多看原创技术文章代理模式相关代码→跟踪属性访问通过捕获get、set、has等操作,可以监控对象何时何地被访问过constuser={name:'Jake',}constproxy=newProxy(user,{get(target,property,receiver){console.log(`Getting${property}`)returnReflect.get(...arguments)},set(target,property,value,receiver){console.log(`Setting${property}=${value}`)returnReflect.set(...arguments)},})proxy.name//'获取名称',triggerget()拦截proxy.age=27//'Settingage=27',triggerset()拦截hiddenproperty代理的内部实现对外部代码不可见,可以隐藏指定的属性targetobjectconsthiddenProperties=['foo','bar']//隐藏键consttargetObject={//目标对象foo:1,bar:2,baz:3,}constproxy2=newProxy(targetObject,{get(目标,属性){如果(hiddenProperties.includes(property)){returnundefined//隐藏属性}else{returnReflect.get(...arguments)}},has(target,property){if(hiddenProperties.includes(property)){returnundefined//隐藏attribute}else{returnReflect.get(...参数)}},})//get()拦截console.log(proxy2.foo)//未定义,隐藏在代理中console.log(proxy2.bar)//未定义,隐藏在代理中console.log(proxy2.baz)//3//has()拦截console.log('foo'inproxy2)//false,隐藏在代理内部console.log('bar'inproxy2)//false,隐藏在代理内部隐藏控制台。log('baz'inproxy2)//true属性验证所有赋值操作都会触发set()捕获,可以根据赋值决定允许还是拒绝赋值consttarget={onlyNumberGoHere:0,}constproxy3=newProxy(target,{set(target,property,value){if(typeofvalue!=='number'){returnfalse}else{returnReflect.set(...arguments)}},})proxy3.onlyNumberGoHere=1//拦截操作,赋值为Number类型console.log(proxy3.onlyNumberGoHere)//1,赋值成功proxy3.onlyNumberGoHere='2'//拦截操作,赋值为String类型console.log(proxy3.onlyNumberGoHere)//1,赋值成功。log(proxy3.onlyNumberGoHere)//1、赋值失败函数和构造函数参数验证可以审查函数和构造函数参数,使函数只接受某一类型的值functionmedian(...nums){returnnums.sort()[Math.floor(nums.length/2)]}constproxy4=newProxy(median,{apply(target,thisArg,argumentsList){for(constargofargumentsList){if(typeofarg!=='number'){//只接受Number类型throw'Non-numberargumentprovided'}}returnReflect.apply(...arguments)},})console.log(proxy4(4,7,1))//4console.log(proxy4(4,7,'1'))//错误:在实例化classUser时,可能需要提供非数字参数才能将参数传递给构造函数{constructor(id){this._id=id}}constproxy5=newProxy(User,{construct(target,argumentsList,newTarget){if(argumentsList[0]===undefined){//必须传递参数throw'Usercannotbeinstantiatedwithoutid'}returnReflect.construct(...arguments)},})newproxy5(1)//newproxy5()//错误:'Usercannotbeinstantiatedwithoutid'databindingandobservableobjectsrunthroughproxy当最初不相关的部分链接在一起:代理类可以绑定到一个全局集合,这样所有创建的实例都被添加到集合中constuserList=[]classUser2{constructor(name){this._name=name}}constproxy6=newProxy(User2,{construct(){constnewUser=Reflect.construct(...arguments)userList.push(newUser)//添加实例到全局集合returnnewUser},})new代理人6('John')newproxy6('Jacob')newproxy6('Jake')console.log(userList)//[User2{_name:'John'},User2{_name:'Jacob'},User2{_name:'Jake'}]可以将集合绑定到事件调度程序,并在每次插入新实例时发送消息consteventList=[]functionemit(newValue){console.log(newValue)/*JohnJacob*/}constproxy7=newProxy(eventList,{set(target,property,value,receiver){console.log(target,property,value)/*[]0John['John']length1['John']1Jacob['John','Jacob']length2*/constresult=Reflect.set(...arguments)if(result&&property!=='length'){emit(value)}returnresult},})proxy7.push('John')proxy7.push('Jacob')总结&问题使用代理写一段代码来监控某个对象何时何地被访问使用代理写一段代码隐藏对象的指定属性目标对象使用代理写一段代码,根据赋值决定是否允许或拒绝给对象赋值使用代理写一段代码,让函数只接受String类型的参数使用代理来写一段代码,让构造函数在实例化时必须传递参数代理类在实例化时被添加到全局集合中。使用代理写一段代码让被代理的集合在每次插入数据时发送一条消息。
