当前位置: 首页 > Web前端 > vue.js

Vue2数据响应原理解析

时间:2023-04-01 01:03:02 vue.js

标题:Vue2数据响应原理解析日期:2022-04-28来源:ITgo什么是数据响应?当对象本身或者对象属性被读写的时候,我们需要知道数据已经被操作了,并且在这个过程中执行一些函数,比如render函数,我把这个过程定义为数据响应。那么vue是如何实现数据响应的呢?接下来我们通过vue的源码来探究一下响应式数据的起止。响应式数据的源代码在./src/core/observer下。在具体实现上,vue使用了4个核心组件:ObserverDepWatcherSchedulerObserverObserver目的很简单,主要是将一个普通的对象转换为响应式对象。那么Observer是如何将一个普通的对象转化为响应式对象的呢?为了实现这一点,Observer通过object.defineProperty将一个普通的对象包装成一个具有getter/setter属性的特殊对象。访问属性时会调用getter,修改属性时会调用setter。这样,我们就可以知道数据何时被读取或写入。知道了实现逻辑,我们来实现一个简单的响应式数据吧!首先我们先定义一个普通对象constobj={a:1,b:2}console.log(obj);显然,这个对象没有响应,从控制台输出可以看出。接下来我们通过Object.defineProperty重写上面的对象letobj={b:2}letval=1Object.defineProperty(obj,'a',{enumerable:true,configurable:true,get(){console.log('aisRead')returnval},set(newVal){console.log('ahasbeenmodified')obj.a=newVal}})现在很明显a属性和b属性是完全不同的,当当a的读写正确,就会返回对应的getter/setter方法。Observer的核心代码如下:exportclassObserver{value:any;部门:部门;vmCount:数量;//以该对象为根的vms数量$dataconstructor(value:any){this.value=valuethis.dep=newDep()this.vmCount=0/**将Observer实例绑定到的__ob__属性data,*observing时会先检测是否已经有__ob__对象存放Observer实例,*def方法定义可以参考https://github.com/vuejs/vue/blob/dev/src/core/util/lang.js#L16*/def(value,'__ob__',this)if(Array.isArray(value)){if(hasProto){protoAugment(value,arrayMethods)/*直接覆盖原型的方法来修改目标对象*/}else{copyAugment(value,arrayMethods,arrayKeys)/*定义(覆盖)目标对象或数组的一个方法*/}/*如果是数组,需要遍历数组,将数组中的所有元素都转换成响应式的可以检测到的元素*/this.observeArray(value)}else{/*如果是对象,直接走绑定*/this.walk(value)}}从Observer的源码可以看出Observer对对象和数组的响应不同。如果是对象,直接调用walk,遍历每一个对象,给它们绑定getter和setter。如果是数组那么就需要遍历数组,将数组中的所有元素都转换成可以检测到的响应式的1.Objectwalk(obj:Object){constkeys=Object.keys(obj)/*walkmethodwill遍历对象的每个属性执行defineReactive绑定*/for(leti=0;i;constructor(){this.id=uid++this.subs=[]}/*添加一个观察者对象*/addSub(sub:Watcher){this.subs.push(sub)}/*移除一个观察者对象*/removeSub(sub:Watcher){remove(this.subs,sub)}/*依赖集合,当Dep.target存在时添加观察者对象*/depend(){if(Dep.target){Dep.target.addDep(this)}}/*通知所有订阅者*/notify(){//首先稳定订阅者列表constsubs=this.subs.slice()if(process.env.NODE_ENV!=='production'&&!config.async){//如果不运行异步,subs不会在调度程序中排序//我们需要ed现在对它们进行排序以确保它们以正确的顺序触发//subs.sort((a,b)=>a.id-b.id)}for(leti=0,l=subs.length;i

a:{{obj.a}}

b:{{obj.b}}

AddB
//js