<>强导语:强>
本文是对Vue官方文档深入响应式原理(https://cn.vuejs.org/v2/guide/reactivity.html)的理解,并通过源码还原实现过程。
响应式原理可分为两步,依赖收集的过程与触发——重新渲染的过程。依赖收集的过程,有三个很重要的类,分别是观察者,环保局,观察者。本文主要解读观察者。
这篇文章讲解上篇文章没有覆盖到观察者的部分的内容,还是先看官网这张图:
观察者最主要的作用就是实现了上图中触摸拼(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源码分析之观察者实现过程