Vue.js原理分析之观察者模块详解

  

  

观察者是Vue核心中最重要的一个模块(一个人认为),能够实现视图与数据的响应式更新,底层全凭观察者的支持。

  

本文是针对Vue@2.1.8进行分析

  

观察者模块在Vue项目中的代码位置是src/核心/观察者,模块共分为这几个部分:

  
      <李>观察者:数据的观察者,让数据对象的读写操作都处于自己的监管之下李   <李>观察家:数据的订阅者,数据的变化会通知到观察者,然后由观察者进行相应的操作,例如更新视图   <李> Dep:观察者与观察者的纽带,当数据变化时,会被观察者观察到,然后由Dep通知到观察者
      李   
  

<强>示意图如下:

  

 Vue.js原理分析之观察者模块详解

  

  

观察者类定义在src/核心/观察者/index.js中,先来看一下观察者的构造函数

        构造函数(价值:有){   这一点。值=https://www.yisu.com/zixun/value   this.dep=new Dep ()   这一点。vmCount=0   def(价值、“__ob__”)   如果(Array.isArray(值)){   常量增加=hasProto   & # 63;protoAugment   :copyAugment   增加(价值、arrayMethods arrayKeys)   this.observeArray(值)   其他}{   this.walk(值)   }   }      

价值是需要被观察的数据对象,在构造函数中,会给价值增加__ob__属性,作为数据已经被观察者观察的标志。如果价值是数组,就使用observeArray遍历值,对价值中每一个元素调用观察分别进行观察。如果价值是对象,则使用走遍历值上每个键,对每个关键调用defineReactive来获得该键的设置/获取控制权。

  

<>强解释下上面用到的几个函数的功能:

  
      <李> observeArray:遍历数组,对数组的每个元素调用观察李   <李>观察:检查对象上是否有__ob__属性,如果存在,则表明该对象已经处于观察者的观察中,如果不存在,则新观察员来观察对象(其实还有一些判断逻辑,为了便于理解就不赘述了)   <李>走:遍历对象的每个键,对对象上每个关键的数据调用defineReactive李   <李> defineReactive:通过Object.defineProperty设置对象的关键属性,使得能够捕获到该属性值的设置/获取动作,一般是由观察者的实例对象进行得到操作,此时观察者的实例对象将被自动添加到Dep实例的依赖数组中,在外部操作触发了设置时,将通过Dep实例的通知来通知所有依赖的观察家进行更新。   
  

如果不太理解上面的文字描述可以看一下图:

  

 Vue.js原理分析之观察者模块详解

  


  

  

Dep是观察者与观察者之间的纽带,也可以认为Dep是服务于观察者的订阅系统.Watcher订阅某个观察者的环保局,当观察者观察的数据发生变化时,通过Dep通知各个已经订阅的观察家。

  

<强> Dep提供了几个接口:

  
      <李> addSub:接收的参数为观察者实例,并把观察者实例存入记录依赖的数组中李   <李> removeSub:与addSub对应,作用是将观察者实例从记录依赖的数组中移除李   <李>:取决于Dep.target上存放这当前需要操作的观察家实例,调用依赖会调用该观察者实例的addDep方法,addDep的功能可以看下面对观察者的介绍李   <李>通知:通知依赖数组中所有的观察家进行更新操作李   
  


  

  

观察者是用来订阅数据的变化的并执行相应操作(例如更新视图)的.Watcher的构造器函数定义如下:

        构造函数(vm, expOrFn、cb、期权){   这一点。vm=vm   vm._watchers.push(这)//选项   如果(选项){   this.deep=! ! options.deep   这一点。用户=! ! options.user   这一点。懒=! ! options.lazy   这一点。同步=! ! options.sync   其他}{   this.deep=S没?@炼璧?M?false   }   这一点。cb=cb   这一点。id=+ + uid//批处理的uid   这一点。积极=true   这一点。肮脏的=@炼璧?/懒惰的观察者   this.deps=[]   这一点。newDeps=[]   this.depIds=新的()   这一点。newDepIds=新的()   这一点。=process.env表达式。NODE_ENV !==吧?   & # 63;expOrFn.toString ()   :“   如果(typeof expOrFn===昂?{   这一点。getter=expOrFn   其他}{   这一点。getter=parsePath (expOrFn)   如果(! this.getter) {   这一点。getter=function () {}   过程。NODE_ENV !==?,警告(   “失败看路径:“$ {expOrFn} " +   ”观察家只接受简单的点号分隔路径。' +   的完全控制,而是使用一个函数。,   虚拟机   )   }   }   这一点。值=https://www.yisu.com/zixun/this.lazy   吗?未定义的   :this.get ()   }

Vue.js原理分析之观察者模块详解