在 Vue 初始化阶段的时候,会执行 _init 方法,其中在 _init 方法中会执行 initState 方法。在 initState 方法中,我们会对 props ,methods ,data,computed,watch 进行初始化。在我们这篇文章中,主要分析的是 Vue 的数据的响应式,所以我们着重分析 props 和 data 。

首先,我们来看一下 initProps 过程。

initProps 其实就做了两件事,遍历 props ,然后调用 defineReactive 方法把每一个 prop 对应的值变成响应式,可以通过 vm._props.xx 访问到定义 props 中对应的属性。然后我们看看 initData 做了什么。

遍历 data 上的值,先做合法性检测,然后调用 observe 来观察整个 data,很明显 observe 的内部还是会调用 defineReactive 方法的。

我们可以看到,observe 非常简单,如果没有 __ob__ 属性,就实例化一个 Observer ,如果有就直接返回 ob 即可。所以问题关键是 Observer 中发生了什么。

Observer 的构造函数也很简单,实例化了一个 Dep 对象,然后把自身实例添加到对象 value 的 __ob__ 的属性上,该属性不可枚举。最后判断 value ,如果是数组就调用 observeArray 方法,否则就调用 walk 方法。 因为 defineReactive 是对对象上的属性进行响应式,所以 walk 方法就是遍历分别对每一个属性执行 definedReactive 方法即可,而 observeArray 因为是 Array,里面的每一项可能是 object,所以是要分别执行 observe 方法。
我们接着来看一下 definedReactive 的实现,它的主要功能就是把对象中的属性变成响应式。

该方法先初始化了一个 Dep 的实例,接着拿到 obj 的属性描述符,然后对子对象递归调用 observe 方法,这样就保证了无论 obj 结构多复杂,都能够对其属性的每一项及其子属性变成响应式对象,这样我们访问或修改 obj 中一个嵌套层级比较深的属性,也能够触发 getter 和 setter。最后利用 Object.defineProperty 去给 obj 的属性 key 添加 getter 和 setter。其中 getter 做的就是依赖收集,setter 做的就是派发更新。

本文深入剖析Vue.js中数据响应式的实现机制,包括props和data的初始化过程,以及如何通过Observer和defineReactive方法使数据变得响应式。

8816

被折叠的 条评论
为什么被折叠?



