Object.defineProperty直接在一个对象上定义一个新的属性,或者修改一个对象已有的属性,并返回这个对象。constproxy=function(target,key){让值;Object.defineProperty(target,key,{set(val){value=val;console.info('set')},get(){console.info('get')返回值;}})}constobj=对象.create(null);代理(obj,'arr');obj.arr=[];打印出'set'在Vue中的应用众所周知,Vue的Data更新触发页面渲染,它使用Object.defineProperty来监控对象属性集。Object.defineProperty(obj,key,{enumerable:true,configurable:true,get:functionreactiveGetter(){varvalue=getter?getter.call(obj):val;if(Dep.target){dep.depend();if(childOb){childOb.dep.depend();if(Array.isArray(value)){dependArray(value);}}}返回值},set:functionreactiveSetter(newVal){varvalue=getter?getter.call(obj):val;/*eslint-disableno-self-compare*/if(newVal===value||(newVal!==newVal&&value!==value)){return}/*eslint-启用无自我比较*/if(process.env.NODE_ENV!=='production'&&customSetter){customSetter();}if(setter){setter.call(obj,newVal);}else{val=newVal;}childOb=!shallow&&observe(newVal);dep.notify();}});Vue实例初始化时,组件的初始化数据一步步实例化为可观察对象。varObserver=functionObserver(value){this.value=value;this.dep=newDep();这个.vmCount=0;def(值,'__ob__',这个);如果(Array.isArray(value)){varaugment=hasProto?protoAugment:copyAugment;扩充(值,arrayMethods,arrayKeys);this.observeArray(值);}else{this.walk(值);}};它是一个数组。当使用push等方法改变数组时,setconstobj=Object.create(null);proxy(obj,'arr');obj.arr=[];obj.arr.push(1);No会打印出来'set'如果添加的属性值是多级对象,对于深层次修改,不会触发设置//沿用前面的例子proxy(obj,'deepObj');obj.deepObj={a:{b:c:1}}obj.deepObj.a.b.c=2不会打印出'set'Vue对数组更新问题的现有处理Vue重写了Array原型链上的几个方法,这样使用push时,pop、shift、unshift、splice、sort、reverse等方法也可以触发页面刷新。vararrayProto=Array.prototype;vararrayMethods=Object.create(arrayProto);['push','pop','shift','unshift','splice','sort','reverse'].forEach(function(method){//缓存原始方法varoriginal=arrayProto[method];def(arrayMethods,method,functionmutator(){varargs=[],len=arguments.length;while(len--)args[len]=arguments[len];var结果=original.apply(this,args);varob=this.__ob__;varinserted;switch(method){case'push':case'unshift':inserted=args;breakcase'splice':inserted=args.slice(2);break}if(inserted){ob.observeArray(inserted);}//通知变化ob.dep.notify();返回结果});});对于multi-level如果对象没有定义在数据中,直接修改值不会触发页面更新。varvm=newVue({data(){return{a:1};}})vm.a=2;//会触发页面刷新vm.b=3;//此时不会触发页面刷新,如果要更改未定义的属性,需要使用官方推荐的实例$set方法。vm.$set(vm.data,'b',3)//会触发页面刷新大致了解了Vue的数据更新原理后,就可以开始联想Vue3.0的Proxy了~
