选项 data 的合并策略
我们跳过mergeData 以及 mergeDataOrFn,我们暂且不关注这两个函数的作用。暂且跳过继续看下面的代码:
strats.data = function ( parentVal: any, childVal: any, vm?: Component ): ?Function { if (!vm) { if (childVal && typeof childVal !== 'function') { process.env.NODE_ENV !== 'production' && warn( 'The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm ) return parentVal } return mergeDataOrFn(parentVal, childVal) } return mergeDataOrFn(parentVal, childVal, vm) }
在strats策略对象上面添加了一个data策略函数,进行选项data的策略合并
if (!vm) {}如同上一篇文章介绍一样 用来判断是否是子组件选项,
如果是子组件选项 return mergeDataOrFn(parentVal, childVal)
如果不是 return mergeDataOrFn(parentVal, childVal, vm)
再来看看if判断里面的内容:
if (childVal && typeof childVal !== 'function') {}
判断是否又子组件的data,并且检测是否是一个function,如果不是函数则会警告,并且返回parentVal
如果childval是函数 则会返回mergeDataOrFn(parentVal, childVal) 执行结果
后面就不用说了, 如果又vm 就执行mergeDataOrFn(parentVal, childVal, vm)
接下来我们看看一直调用的mergeDataOrFn函数是什么:
/**
* Data
*/
export function mergeDataOrFn (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
// in a Vue.extend merge, both should be functions
if (!childVal) {
return parentVal
}
if (!parentVal) {
return childVal
}
// when parentVal & childVal are both present,
// we need to return a function that returns the
// merged result of both functions... no need to
// check if parentVal is a function here because
// it has to be a function to pass previous merges.
return function mergedDataFn () {
return mergeData(
typeof childVal === 'function' ? childVal.call(this, this) : childVal,
typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal
)
}
} else {
return function mergedInstanceDataFn () {
// instance merge
const instanceData = typeof childVal === 'function'
? childVal.call(vm, vm)
: childVal
const defaultData = typeof parentVal === 'function'
? parentVal.call(vm, vm)
: parentVal
if (instanceData) {
return mergeData(instanceData, defaultData)
} else {
return defaultData
}
}
}
}
整体的也是和之前的几个函数一样 首先对vm的判断,其中就mergeData函数需要介绍下,看下mergeData源码,这个函数是用来干嘛的
/**
* Helper that recursively merges two data objects together.
*/
function mergeData (to: Object, from: ?Object): Object {
// 没有 from 直接返回 to
if (!from) return to
let key, toVal, fromVal
const keys = Object.keys(from)
// 遍历 from 的 key
for (let i = 0; i < keys.length; i++) {
key = keys[i]
toVal = to[key]
fromVal = from[key]
// 如果 from 对象中的 key 不在 to 对象中,则使用 set 函数为 to 对象设置 key 及相应的值
if (!hasOwn(to, key)) {
set(to, key, fromVal)
// 如果 from 对象中的 key 也在 to 对象中,且这两个属性的值都是纯对象则递归进行深度合并
} else if (isPlainObject(toVal) && isPlainObject(fromVal)) {
mergeData(toVal, fromVal)
}
// 其他情况什么都不做
}
return to
}
接收两个参数,to,from;
根据调用传参 to 对应的是 childVal 产生的纯对象,from 对应 parentVal 产生的纯对象
这个函数作用就是:将 from 对象的属性混合到 to 对象中,也可以说是将 parentVal 对象的属性混合到 childVal 中,最后返回的是处理后的 childVal 对象。
合并阶段 strats.data 将被处理成一个函数,但是这个函数并没有被执行,而是到了后面初始化的阶段才执行的,
重点:!!!!!!!!!!!
mergeData 函数只有在初始化的时候才会执行,进行数据合并;
Vue 的初始化的时候, inject 和 props 这两个选项的初始化是先于 data 选项的,这就保证了我们能够使用 props 初始化 data 中的数据