观察者是Vue核心中最重要的一个模块(一个人认为),能够实现视图与数据的响应式更新,底层全凭观察者的支持。
本文是针对Vue@2.1.8进行分析
观察者模块在Vue项目中的代码位置是src/核心/观察者,模块共分为这几个部分:
-
<李>观察者:数据的观察者,让数据对象的读写操作都处于自己的监管之下李>
<李>观察家:数据的订阅者,数据的变化会通知到观察者,然后由观察者进行相应的操作,例如更新视图李>
<李> Dep:观察者与观察者的纽带,当数据变化时,会被观察者观察到,然后由Dep通知到观察者
李>
<强>示意图如下:强>
观察者类定义在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实例的通知来通知所有依赖的观察家进行更新。李>
如果不太理解上面的文字描述可以看一下图:
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原理分析之观察者模块详解