Vue Object 的变化侦测实现代码
数据观察
Vue中的对象变化侦测是通过Object.definePorperty实现的,但是Object.definePorperty的方式有缺陷,比如不能直接代理整个对象,每次都要循环遍历对象的所有属性;尤大大说之后会使用ES6中的Proxy重写这个部分。这篇博客介绍的是Object.definePorperty实现的对象侦测。
我们来看下面这段代码,定义一个defineReactive函数,使用Object.definePorperty遍历对象对象属性的时候,设置get和set;当对象属性被读取的时候触发get,对象属性被设置的时候触发set。这样就完成了对data的数据劫持,因为Vue的思想是响应式的,我们还需要收集这些变化。
functiondefineReactive(data,key,val){ Object.definePorperty(data,key,{ enumerable:true, configurable:true, get:function(){ returnval; } set:function(newVal){ if(val===newVal){return} val=newVal; } }) }
依赖收集
创建一个Dep类,在get中收集依赖,在set中新增依赖
classDep{ constructor(){ this.arr=[] } addSub(sub){ this.arr.push(sub) } removeSub(sub){ remove(this.arr,sub) } depend(){ if(window.target){ this.addSub(window.target) } } notify(){ constarrs=this.arr.slice(); for(leti=0;iObserver和Watcher
我们发现defineReactive函数只能将某一个属性转换为get/set的形式,所以我们需要一个观察者Observer用来帮助递归的侦测所有的key
classObserver{ constructor(value){ this.value=value } if(!Array.isArry(value)){ this.walk(value) } walk(obj){ constkeys=Object.keys(obj) for(leti=0;i当这些依赖收集完成之后,我们要通知谁呢?怎么样能让视图知道有变化更新?我们需要实现一个订阅者Watcher,
每次触发get的时候都将dep指向自己,这样就可以收集到依赖;
每次set的时候都循环调用Watcher的update方法。
classWatcher{ constructor(vm,exp,cb){ this.vm=vm; this.cb=cb; this.exp=exp; this.value=this.get(); } get(){ Dep.target=this;//将当前订阅者指向自己 varvalue=this.vm[exp];//触发getter,添加自己到属性订阅器中 Dep.target=null;//添加完毕,重置 returnvalue; } update(){ constoldVal=this.value; this.value=this.get(); this.cb.call(this.vm,this.value,oldVal) } }当Vue实例挂载好之后,模板都会绑定一个Watcher,谁的属性发生变化了就会通知响应的Watcher,Watcher再去通知编译器Compile进行视图更新
侦测没办法监听到对象上属性的新增和删除
Vue通过Object.definePorperty将对象的key转化为gettersetter的形式来进行侦测,但是无法追踪到属性的新增和删除,所以Vue中提供了vm.get来实现
到此这篇关于VueObject的变化侦测实现代码的文章就介绍到这了,更多相关VueObject变化侦测内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!