数组和对象类型在值变化时是如何被劫持的?A。对象通过Object.defineProperty劫持属性;多个对象通过递归实现。exportfunctiondefineReactive(obj:Object,key:string,val:any,customSetter?:?Function,shallow?:boolean){//1.如果对象不可配置,直接退出constproperty=Object.getOwnPropertyDescriptor(obj,key)if(property&&property.configurable===false){return}//2.获取getter和setterconstgetter=property&&property.getconstsetter=property&&property.set//3.重新定义set和get方法Object.defineProperty(obj,key,{enumerable:true,configurable:true,get:functionreactiveGetter(){constvalue=getter?getter.call(obj):valreturnvalue},set:functionreactiveSetter(newVal){constvalue=getter?getter.call(obj):valif(newVal===value||(newVal!==newVal&&value!==value)){return}if(getter&&!setter)返回if(setter){setter.call(obj,newVal)}else{val=newVal}}})}这个方法只会监听对象自带的属性,新的属性无法监听,所以对于新的属性,使用$set方法添加数据,$set方法会将新的属性定义为响应式数据b。数组被重写为exportconstarrayMethods=Object.create(arrayProto)constmethodsToPatch=['push','pop','shift','unshift','splice','sort','reverse']methodsToPatch.forEach(function(method){//缓存原始方法constoriginal=arrayProto[method]def(arrayMethods,method,functionmutator(...args){constresult=original.apply(this,args)constob=this.__ob__letinsertedswitch(method){case'push':case'unshift':inserted=argsbreakcase'splice':inserted=args.slice(2)break}//再次观察新添加的属性if(inserted)ob.observeArray(inserted)returnresult})})在对数组进行操作时,会调用重写的数组方法,此时可以监听到数据变化。因此,如果修改了数组索引和长度,则不会监听到数组的变化。Vue3中使用了ES6的Proxy,Proxy可以拦截目标对象的底层操作letobj={name:{name:'lh'}}lethandler={get(target,key){//这里的命名必须是同Reflect方法对应if(typeoftarget[key]==='object'&&target[key]!==null){returnnewProxy(target[key],handler);}returnReflect.get(target,key);},set(target,key,value){让oldValue=target[key];if(!oldValue){console.log('newattribute')}elseif(oldValue!==value){console.log('modifyproperty')}returnReflect.set(target,key,value);}}letproxy=newProxy(obj,handler);
