Vue源码分析之观察者实现过程

  

<>强导语:

  

本文是对Vue官方文档深入响应式原理(https://cn.vuejs.org/v2/guide/reactivity.html)的理解,并通过源码还原实现过程。

  

响应式原理可分为两步,依赖收集的过程与触发——重新渲染的过程。依赖收集的过程,有三个很重要的类,分别是观察者,环保局,观察者。本文主要解读观察者。

  

这篇文章讲解上篇文章没有覆盖到观察者的部分的内容,还是先看官网这张图:

  

 Vue源码分析之观察者实现过程

  

观察者最主要的作用就是实现了上图中触摸拼(getter)——收集依赖这段过程,也就是依赖收集的过程。

  

还是以下面的代码为例子进行梳理:

  

(注:左右滑动即可查看完整代码,下同)

        varvm=newVue ({   艾尔:#演示,   数据:{   名字:“你好”,   fullName:“   },   看:{   firstName (val) {   这一点。fullName=val +“TalkingData”;   },   }   })      

在源码中,通过还原Vue进行实例化的过程,从开始一步一步到观察者类的源码依次为(省略了很多不在本篇文章讨论的代码):

     //src/核心//index.js实例   functionVue(选项){   如果(process.env。NODE_ENV !==?,   ! (thisinstanceofVue)   ) {   警告(Vue是一个构造函数,应该被称为“新“关键字”)   }   this._init(选项)   }//src/核心//init.js实例   Vue.prototype。_init=function(选项# 63;:对象){   constvm:组件=//?   initState (vm)//?   }//src/核心//state.js实例   exportfunctioninitState (vm:组件){//?   constopts=vm。选择美元   如果(opts.data) {   initData (vm)   }//?   }   functioninitData (vm:组件){   letdata=https://www.yisu.com/zixun/vm。options.data美元   data=vm。_data=typeofdata===昂?   & # 63;getData(数据,vm)   :数据| | {}//?/观察数据   观察(数据,真正的/* asRootData */)   }      

在initData方法中,开始了对数据项中的数据进行”观察”,会将所有数据的变成可见的。接下来看观察方法的代码:

     //src/核心/观察者/index.js   functionobserve(价值:任何asRootData: & # 63;布尔型):观察者|空白{//如果不是对象,直接返回   如果(! isObject(价值)| |值instanceofVNode) {   返回   }   letob:观察者|空白   如果(hasOwn(价值,“__ob__”),,价值。__ob__ instanceofObserver) {//如果有实例则返回实例   ob=value.__ob__   }elseif (//确保价值是单纯的对象,而不是函数或者是Regexp等情况   observerState。shouldConvert,,   ! isServerRendering (),,   (Array.isArray(价值)| | isPlainObject(值)),,   Object.isExtensible(值),,   value._isVue !   ) {//实例化一个观察者   ob=newObserver(值)   }   如果(asRootData,,ob) {   ob.vmCount + +   }   returnob   }      

观察方法的作用是给数据创建一个观察者实例并返回,如果数据有ob属性了,说明已经有观察者实例了,则返回现有的实例.Vue的响应式数据都会有一个ob的属性,里面存放了该属性的观察者实例,防止重复绑定。再来看新观察员(值)过程中发生了什么:

        exportclassObserver {   价值:任何;   管理:管理;   vmCount:数量;//美元这个对象作为根用户的虚拟机数量的数据   构造函数(价值:有){   这一点。值=https://www.yisu.com/zixun/value   this.dep=newDep ()   这一点。vmCount=0   def(价值、“__ob__”)   如果(Array.isArray(值)){//?   this.observeArray(值)   其他}{   this.walk(值)   }   }   走(obj:对象){   constkeys=种(obj)   (leti=0;我& lt;keys.length;我+ +){   defineReactive (obj键[我],obj[[我]]键)   }   }   observeArray(项目:Array      

通过源码可以看的到,实例化观察者过程中主要是做了两个判断。如果是数组,则对数组里面的每一项再次调用伯方法进行观察;如果是非数组的对象,遍历对象的每一个属性,对其调用defineReactive方法。这里的defineReactive方法就是核心!通过使用Object.defineProperty方法对每一个需要被观察的属性添加获?设置,完成依赖收集。依赖收集过后,每个属性都会有一个Dep来保存所有观察家对象。按照文章最开始的例子来讲,就是对firstName和fullName分别添加了获?设置,并且它们各自有一个Dep实例来保存各自观察它们的所有观察家对象。下面是defineReactive的源码:

Vue源码分析之观察者实现过程