首先我希望你能够读完因为他确实对你有一点帮助。我给大家准备了一张便于理解的图话不多说我们直接上干货。首先看下Vue的构造函数classVue{constructor(options{}){this.eloptions.elthis.expoptions.expthis.dataoptions.data el.innerHTMLthis.data[this.exp]// 初始化页面内容letobservernewObserver()observer.defineReactive(this.data)newWatcher(this,this.exp,function(val){//创建watcher实例调用构造函数。el.innerHTMLval})returnthis}}从构造函数当中我们可以得到的信息如下首先是对this.data进行了observer的操作new Watcher将当前的this传了进去Observer是什么defineReactive又是什么先来看下Observer代码如下exportclassObserver{constructor(value){this.valuevalue;if(!Array.isArray(value)){this.walk(value);}}walk(obj){constkeysObject.keys(obj);for(leti0;ikeys.length;i){defineReactive(obj,keys[i],obj[keys[i]]);}}}functiondefineReactive(data,key,val){// 新增递归子属性if(typeofvalobject){newObserver(val);}letdepnewDep();Object.defineProperty(data,key,{enumerable:true,configurable:true,get:function(){dep.depend();// *******returnval;},set:function(newVal){if(valnewVal){return;}valnewVal;dep.notify();// -------},});}可以看到Observer对象当中有一个函数叫做defineReactive刨析这个函数可以我们可以看到其实是Object.defineProperty的一个封装操作。我们知道Object.defineProperty是对传入的参数对象进行递归遍历并为该对象的每一个属性添加对应的setget方法也就是我们熟知的数据劫持或者称为数据拦截。再然后我们知道setget方法都有它各自的作用get当中收集依赖而set当中触发依赖。我们再看发现他在这里进行了new dep的操作。dep对象又是用来做什么的呢我们接着看。exportdefaultclassDep{constructor(){this.subs[];}addSub(sub){// 收集依赖this.subs.push(sub);}removeSub(sub){// 移除依赖remove(this.subs,sub);}// depend通过判断window.target也就是当前的watcher实例对象是否存在调用addSubdepend(){if(window.target){this.addSub(window.target);}}notify(){// 通知也就是数据改变之后的更新操作constsubsthis.subs.slice();for(leti0,lsubs.length;il;i){subs[i].update();// update方法在watcher当中}}}functionremove(arr,item){// 移除依赖if(arr.length){constindexarr.indexOf(item);if(index-1){returnarr.splice(index,1);}}}我们看到在defineReactive这个方法的get方法中调用了dep.depend();在方法有*号标注的地方。然后我们回到class Dep当中首先是初始化声明了一个依赖数组然后在depend方法中判断了一下window.target是否存在存在则调用addSub添加依赖。到这里很多人其实会比较疑惑window.target是什么我先说一下就是下面要将到的Watcher对象现在你只需要把它看成一个依赖就可以了。再看set方法调用了dep.notify();同样的我们去找一下这个方法他对当前的一个subs进行了循环调用subs当中每一项的update方法。update方法是watcher对象的一个方法到这里Vue构造函数当中的observer.defineReactive(this.data)这一步就已经结束了 。到这里的话其实我们已经为传入的this.data添加了对应的set和get方法但是并没有收集到对应的依赖因为此时window.target的值一直是undefined。现在所有的准备工作都已经做好了。只缺少了一个关键点去触发而这个关键点就在watcher当中。最后我们需要看一下这个Watcher了。Watcher又是什么exportdefaultclassWatcher{constructor(vm,expOrFn,cb){this.vmvm;// 执行this.getter()就可以读取data.a.b.c的内容this.getterparsePath(expOrFn);this.cbcb;this.valuethis.get();}get(){window.targetthis;// 这就与上面联系起来了this指向当前的实例对象letvaluethis.getter.call(this.vm,this.vm);// 获取当前的valuewindow.targetundefined;returnvalue;}update(){constoldValuethis.value;this.valuethis.get();this.cb.call(this.vm,this.value,oldValue);}}我们看Watcher发现他会在构造函数constructor当中读取传入的data的值。详细看get方法内容会发现此时的this肯定就是当前的watcher实例对象了对吧再看Watcher对象的get方法第一句就是window.target this将window.target的值指向了当前的Watcher。然后let value this.getter.call(this.vm, this.vm);此时去读取了值。要知道在进行这一步之前我们就已经为data添加了数据拦截那么这个时候我们去读取它的值肯定会触发拦截。也就是defineReactive当中的get方法里面的dep.depend。由此收集到了对应的依赖数组当数据发生变化的时候触发set方法循环对应的依赖数组调用其update方法触发依赖使得数据视图发生变化。到此就结束了这个还是需要大家多去串联一下他们之间的关系才能融会贯通。好了下课