vue源码解析之选项合并(二)

选项 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 中的数据

猜你喜欢

转载自www.cnblogs.com/xweizi/p/10551938.html