dedupe 函数

正如注释所说,dedupe 函数“比较 latest 和 sealed ,以确保 merge 时,生命周期钩子不会重复”:

function dedupe (latest, extended, sealed) {
  // compare latest and sealed to ensure lifecycle hooks won't be duplicated
  // between merges
  if (Array.isArray(latest)) {
    const res = []
    sealed = Array.isArray(sealed) ? sealed : [sealed]
    extended = Array.isArray(extended) ? extended : [extended]
    for (let i = 0; i < latest.length; i++) {
      // push original options and not sealed options to exclude duplicated options
      if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) {
        res.push(latest[i])
      }
    }
    return res
  } else {
    return latest
  }
}

首先,dedupe 函数在 if 语句中调用 Array.isArray,并把 latest 作为参数,来检测 latest 是否是一个数组。

然后,初始化一个变量 res ,值为空数组。

接着,为了确保 sealed 是数组,通过调用三元运算符重置了 sealed。如果是数组,sealed 设为 sealed(例如,dedupe 函数的参数 sealed)。如果不是数组,就用一个数组包裹下 sealed。设置 extended 时,也是同 sealed 一样。

sealed = Array.isArray(sealed) ? sealed : [sealed]
extended = Array.isArray(extended) ? extended : [extended]

接下来,dedupe 函数遍历 latest 数组:调用 indexOf 方法来判断 latest 数组中的当前项是否在 extended 数组中,或者不在 sealed 中,如果条件成立,这些选项就会被 push (追加)到 res 数组里。遍历完后,再返回数组 res

for (var i = 0; i < latest.length; i++) {
  if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) {
    res.push(latest[i])
  }
}
return res

然而,如果表达式 Array.isArray(latest) 的值为 falsededupe 函数返回 latest


跳到 resolveModifiedOptions 函数,现在我们理解了通过遍历构造函数的选项属性,判断哪些选项被更改了,如果被更改了,映射一个更改项的对象,并且返回出去。

for (const key in latest) {
  if (latest[key] !== sealed[key]) {
    if (!modified) modified = {}
    modified[key] = dedupe(latest[key], extended[key], sealed[key])
  }
}
return modified

最后,我们回到 resolveConstructorOptions ,这个函数在初始化 modifiedOptions 变量时,通过传给 resolveModifiedOptions 函数一个构造函数作为参数设置变量的值。

function resolveConstructorOptions (Ctor) {
  // ...
  const modifiedOptions = resolveModifiedOptions(Ctor)
  // ...
}

因此,modifiedOptions 的值将是一个被更改过的选项 options 的对象。


resolveConstructorOptions 函数然后检测下是否有选项被更改了,如果更改了,调用我们之前讨论过的 extend 函数,所传参数为构造函数的 extendOptions 属性和 modifiedOptions 变量。回一下,extend 函数遍历第二个参数,这里就是 modifiedOptions,然后把第二个参数的每个键的值设置为第一个参数对应键的值。

再次调用 mergeOptions ,并把返回值设置给 optionsCtor.options

然后,检查 options.name 是否为 true 。如果为真,把 options.components 上名为 options.name 的属性设置为构造函数 Ctor 。最后,把变量 options 返回。

function resolveConstructorOptions (Ctor) {
  // ...
  options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
  if (options.name) {
    options.components[options.name] = Ctor
  }
  return options
}

在这些基础上,最后我们可以返回到 ._init 方法中。._init 方法通过调用 mergeOptions 函数,并传3个参数,设置了一个 $options 属性:

// ...
vm.$options = mergeOptions(
  resolveConstructorOptions(vm.constructor),
  options || {},
  vm
)
// ...

在以上的讨论中,现在我们理解了传给 mergeOptions 函数的第一个参数:resolveConstructorOptions(vm.constructor) 。在下一章,我们将更详细的讨论 mergeOptions 方法。

上次更新: 1/24/2019, 5:44:12 AM