vue源码解读--响应式的创建过程

目录导航

本节的示例如下

vue源码解读--响应式的创建过程_第1张图片
(app.vue组件在main.js中引入)

当new vue的时候将执行init方法,在该方法中将调用initState

vue源码解读--响应式的创建过程_第2张图片

        这里有两个地方比较重要,一个是initProps,一个是initData

        我们本节没有props数据,故着重看data是如何被set为响应式的

vue源码解读--响应式的创建过程_第3张图片

                我们示例的data是一个函数,故调用getData方法,传入data和vm实例

vue源码解读--响应式的创建过程_第4张图片

                该方法将修正this指向,使其指向vm实例,因此data拿到的就是一个this指向vm的对象,因此我们可以在组件内通过this._data拿到data中的值,因此最终拿到的data是一个对象,如果不是,则报警告,即isPlainObject为false

                接着拿到data、props和methods的键名去遍历比对,如果发现data中的键在props或者methods中同名,则报警告,同时针对键名也做了限制,比如不能以_或$开头等

                接着调用observe对data进行观察(观察者模式),并将data传入

vue源码解读--响应式的创建过程_第5张图片


                        vue要求value必须是一个对象,且不能是vnode

                        显然,作为第一次,value上是没有__ob__属性的,因此进入else逻辑

                        shouldObserve是在全局定义的值,默认为true,即应该对该对象进行观测,同时提供了toggleObserving方法去控制跳过某些不需要观测的值

                        isServerRendering用于检测当前的代码环境,我们这里是在浏览器环境故进入else,返回false

vue源码解读--响应式的创建过程_第6张图片

                        我们的value是对象,故isPlainObject为true

                        isExtensible是原生Object提供的检测目标对象是否可扩展,需要手动调用preventExtensions置为false否则默认是可扩展的,故我们这里是true

                        _isVue在vue的时候为true,因此这里为false

                实例化Observer

vue源码解读--响应式的创建过程_第7张图片

                        向Observer的value保存一份data

                        向Observer的dep保存一份Dep实例,这里的Dep实际上充当的就是"发布者"

vue源码解读--响应式的创建过程_第8张图片

                        调用def,def实际是对Object.defineProperty的封装

vue源码解读--响应式的创建过程_第9张图片
(该接口允许向对象添加或修改key,同时向每个key定义属性规则)

                               在这里向value添加了私有属性"__ob__",该值是不可枚举的,且它的值引用的是Observer实例

                        我们这里的value是对象,故走else逻辑,调用walk方法

                                    在这里遍历value的每一个key并调用defineReactive将value和键值传入,由于我们将__ob__设置为不可枚举,故实际上只会执行一次,即key="meta"

vue源码解读--响应式的创建过程_第10张图片

                                      首先,再次实例化dep

                                     通过Object.getOwnPropertyDescriptor获取对象的属性描述符,默认情况下符合if判断

                                     默认是没有get和set的,故getter=undefined,setter=undefined,调用该函数时传递的实参只有两个,故符合if判断。val=obj.msg,即我们在data中定义的{msg:"腊八节快乐呀!"}

                                    接着继续对val尝试进行观测,由于是一个对象,因此会再次执行到当前位置,下一次的值为msg是一个基本数据类型  String,故向下调用Object.defineProperty,定义get和set。其中get将在每次访问时进行依赖收集,set则主要做派发更新

当msg被通过Object.defineProperty定义过get和set后,将会返回到上一次值为{msg:"腊八节快乐呀!"},并对该对象设置set和get,接着继续返回meta.......,也就是说,vue会进行深度遍历,对每一个值都添加set和get同时每一个值都添加了私有的__ob__。这样当访问不管是哪一个值时都架设了一层拦截器


那么,set和get到底做了什么呢?(依赖收集)(派发更新)

你可能感兴趣的:(vue源码解读--响应式的创建过程)