Vue 源码(七):Vue

接下来,我们把 strats.data 给它完善一下。

首先,我们要明确一点,我们这些自定义的策略其实就是围绕着组件,和这些子类来做限制的。

说白了,就是不能够让你乱来。

那么回到代码,如果说我们传入的 childVal 数据类型是 function,那我们会直接调用一个 mergeDataOrFn 的方法,来做一些数据的合并。

那如果说,我们是通过 Vue 的实例来调用 strats.data 这个方法的时候,我们也会来进行数据的处理,这里就会直接返回一个函数了。

首先,我们先来看一个东西,我们直接引用源码。

打印 vm.$options

我们可以看到,data 属性对应的是一个叫做 mergedInstanceDataFn 函数。

那么我们就肯定会有一个疑问,它不是应该为一个对象吗?

其实这是 Vue 给我们所做的一个设计,data 在这个选项最终输出的时候,不管是子组件,还是 Vue 的实例也好,它最终输出的 data 选项的值,都是一个函数。

那么它是怎么实现的呢? 

分为两个步骤,一个是在子组件和子类里面调用 strats.data,一个是 Vue 的实例来调用这个方法。

如果我们是通过组件或子类来调用 strats.data,那么我们就会来进行合并的处理,那此时,我们传入的 parentVal 和 childVal 它们都应该是函数。

如果是 Vue 的实例来调用,那么我们最终会返回一个叫做 mergedInstanceDataFn 的方法。

Vue 的源码是这样来处理的:

如果 childVal 没值,就直接 return parentVal。

如果 parentVal 是没有值的,就直接 return childVal。

那么写到这里,肯定会有一个疑问,为什么要写这样一个代码呢?

因为我们有一些特殊的情况下,childVal存在,而parentVal不存在。

同时也有一些情况下,parentVal存在,而childVal不存在。

那么我们来举个例子说明一下:

假设 childVal 是有值的,说明我们传入了一个 data 的配置。

然后我们可以打印下 parentVal 和 childVal。

我们可以看到 parentVal 是 undefined,但是 childVal 是一个匿名函数。

那为什么 parentVal 的值是 undefined 呢?

因为这个 parentVal 是作为 Vue.options 里面来进行检测的。

其实就是检测 Vue.options 里面有没有 data 这个选项。

那么问题来了,如果说 childVal 是没有传的,那么我们返回一个 undefined 的意义在哪里呢?

所以我们还有另外一种情况,parentVal 是有值的,但是 childVal 是没有值的。

那么这种情况在哪里会碰到呢?我们继续来举个例子:

我们可以看到 Parent.extend(),那么 Parent 是什么呢?

Parent 就是在调用 Vue.extend 所返回子类的构造函数本身,也就是 initExtend 函数里面 return 的 Sub。

那么我们还可以通过 Sub 来调用 extend 方法吗?

其实是可以的,因为在 Vue 的设计中,也会在给 Sub 拓展一个 extend 的方法。

所以我们就可以通过 Parent 来调用 extend 这个方法了。

那么出现在这种情况下,我们就会发现 parentVal 是有值的,但是 childVal 就没有值了。

然后回到源码,接下来,如果说 parentVal 和 childVal 都有值,那么就会合并,那么是怎么进行合并的呢?

首先,我们定义一个 mergeDataOrFn 方法。

然后我们可以把检测的内容也放进去,这样的话,我们在 strats.data 里面就只需要检测是子组件,子类来调用还是 Vue 的实例来调用。

那么不管作为谁来调用,我们把数据最终的都统一在 mergeDataOrFn 方法里面来进行处理。

唯一不同的是有没有传 vm。

如果 vm 是没有值的,我们就是作为子组件子类来进行处理。

如果 vm 是有值的,我们才是真正的来处理数据的合并。

那么在 mergeDataFn 里面我们怎么来进行合并呢?

我们可以直接 return mergeData() 这个方法,其实我们所有的合并都会在 mergeData 里面来进行实现。

在 mergeData 里面我们唯一要做的事情,就是怎么给它传值。

我们可以做一个三元表达式,如果说 childVal 是一个函数,那我们就直接调用并把返回值传递过去。如果不是函数,就把 childVal 本身给传过去。

parentVal也是同理。

那么在 Vue 的实例里面,我们怎么来处理 data 呢?很显然,和上面的处理都是一样的。

然后我们就来进行检测。

如果说我们当前创建 Vue 实例的 data 是有值的,那我们就可以直接去调用 mergeData 这个方法,来进行终极的合并。

那如果说我们创建 Vue 实例的时候,data 没有传呢,那么就直接返回 defaultData,也就是 undefined。

然后我们在打印 vm.$options,我们可以看到 data 它对应的永远是个函数。

我们可以看到,在 mergeDataOrFn 里面,我们返回的仅仅是一个函数,我们并没有调用。

这也是为什么我们没有定义 mergeData 这个函数,它却没有报错的原因。

那么 mergeData 这个函数在什么情况下去调用呢?

当我们加入到响应式系统中的时候,当我们再来进行数据初始化的时候,我们就需要去调用它。

mergeData 是一个终极的合并,它里面最多的其实就是针对于子组件和子类一些数据的合并。

如果 from 不存在,我们就直接return to,也就是 instenceData,而 instenceData 也就是我们所传过去的 data。

至于剩下的,就需要加入到响应式中在继续完善了。

发布了61 篇原创文章 · 获赞 3 · 访问量 4384

猜你喜欢

转载自blog.csdn.net/weixin_43921436/article/details/102489993
vue