资讯专栏INFORMATION COLUMN

人人都能懂的Vue源码系列—04—resolveConstructorOptions函数-下

My_Oh_My / 3543人阅读

摘要:上一篇文章中说道,函数要分两种情况进行说明,第一种是为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况,是创建的子类。表示的是当前构造器上新增的,表示的是当前构造器上新增的封装。

上一篇文章中说道,resolveConstructorOptions函数要分两种情况进行说明,第一种是Ctor为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况,Ctor是Vue.extend创建的"子类"。

Ctor是Vue.extend创建的"子类"

Vue.extend方法我们之后的博文再进行详细介绍,这里大家可以先把Vue.extend的功能笼统的理解为继承。我们接下来看resolveConstructorOptions相关的代码,如果Ctor是Vue.extend创建的"子类",那么在extend的过程中,Ctor上就会有super属性。

Vue.extend = function (extendOptions: Object): Function {
  ...
  Sub["super"] = Super
  ...
}

Ctor上有了super属性,就会去执行if块内的代码

...
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
...
// Vue.extend相关代码
Vue.extend = function (extendOptions: Object): Function {
  ...
  Sub.superOptions = Super.options // Sub.superOptions指向基础构造器的options
  ...
}

首先递归调用resolveConstructorOptions方法,返回"父类"上的options并赋值给superOptions变量。然后把"自身"的options赋值给cachedSuperOptions变量。
然后比较这两个变量的值,当这两个变量值不等时,说明"父类"的options改变过了。例如执行了Vue.mixin方法,这时候就需要把"自身"的superOptions属性替换成最新的。然后检查是否"自身"d的options是否发生变化。resolveModifiedOptions的功能就是这个。

if (superOptions !== cachedSuperOptions) {
      // super option changed,
      // need to resolve new options.
      Ctor.superOptions = superOptions
      // check if there are any late-modified/attached options (#4976)
      const modifiedOptions = resolveModifiedOptions(Ctor)
      ....
    }

说了这么多,大家可能还是有点陌生,我们直接举个例子来说明一下。

  var Profile = Vue.extend({
     template: "

{{firstName}} {{lastName}} aka {{alias}}

" }) Vue.mixin({ data: function () { return { firstName: "Walter", lastName: "White", alias: "Heisenberg" } }}) new Profile().$mount("#example")

由于Vue.mixin改变了"父类"options。源码中superOptions和cachedSuperOptions就不相等了,大家可以去jsfiddle试试效果。
接下来看看resolveModifiedOptions都干了哪些事情?

function resolveModifiedOptions (Ctor: Class): ?Object {
  let modified // 定义modified变量
  const latest = Ctor.options // 自身的options
  const extended = Ctor.extendOptions // 构造"自身"时传入的options
  const sealed = Ctor.sealedOptions // 执行Vue.extend时封装的"自身"options,这个属性就是方便检查"自身"的options有没有变化
 // 遍历当前构造器上的options属性,如果在"自身"封装的options里没有,则证明是新添加的。执行if内的语句。调用dedupe方法,最终返回modified变量(即”自身新添加的options“)
  for (const key in latest) {
    if (latest[key] !== sealed[key]) {
      if (!modified) modified = {}
      modified[key] = dedupe(latest[key], extended[key], sealed[key])
    }
  }
  return modified
}

那么dedupe方法又干了什么事情呢?

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
  }
}

从作者的注释可以看到这个方法主要就是防止生命周期构造函数重复。我们再来看该方法传入的3个参数。latest,extended,sealed,lateset表示的是"自身"新增的options。extended表示的是当前构造器上新增的extended options,sealed表示的是当前构造器上新增的封装options。
回到源码,如果latest不是数组的话(lateset是"自身"新增的options),这里不需要去重,直接返回latest。如果传入的latest是数组(如果latest是数组,一般这个新增的options就是生命周期钩子函数),则遍历该数组,如果该数组的某项在extended数组中有或者在sealed数组中没有,则推送到返回数组中从而实现去重。(这个去重逻辑目前自己还不是特别明白,之后如果明白了会在这里更新,有明白的同学们请在评论区留言)
现在我们了解了resolveModifiedOptions和dedupe方法的作用,接下来回到resolveConstructorOptions源码。

  if (modifiedOptions) {
    extend(Ctor.extendOptions, modifiedOptions)
  }
  options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
  if (options.name) {
    options.components[options.name] = Ctor
  }

如果”自身“有新添加的options,则把新添加的options属性添加到Ctor.extendOptions属性上。调用mergeOptions方法合并"父类"构造器上的options和”自身“上的extendOptions(mergeOptions在下一篇博文中介绍),最后返回合并后的options。

看到这里,可能会感觉到头晕,为了让大家更好的理解。我们来看下面的流程图。

下篇博客我们主要讲mergeOptions方法,在整个Vue中属于比较核心的一个方法。敬请期待!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94629.html

相关文章

  • 人人都能懂的Vue源码系列04resolveConstructorOptions函数-

    摘要:上一篇文章中说道,函数要分两种情况进行说明,第一种是为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况,是创建的子类。表示的是当前构造器上新增的,表示的是当前构造器上新增的封装。 上一篇文章中说道,resolveConstructorOptions函数要分两种情况进行说明,第一种是Ctor为基础构造器的情况,这个已经向大家介绍过了,今天这篇文章主要介绍第二种情况...

    BlackHole1 评论0 收藏0
  • 人人都能懂的Vue源码系列—03—resolveConstructorOptions函数-上

    摘要:上篇文章介绍了构造函数的部分实现,当前实例不是组件时,会执行方法。这个文件就是对构造函数进行的第一层包装了。但是注意这里的代码我们构造函数的第二层包装,就在这个文件里了。回到的源码中,当不存在时,直接返回基础构造器的。 上篇文章介绍了Vue构造函数的部分实现,当前Vue实例不是组件时,会执行mergeOptions方法。 vm.$options = mergeOptions( re...

    snifes 评论0 收藏0
  • 人人都能懂的Vue源码系列—02—Vue构造函数

    摘要:果然我们找到了的构造函数定义。告诉你是一个构造函数,需要用操作符去调用。在深入方法之前,我们先把目光移到文件里在的构造函数定义之后,有一系列方法会被立即调用。下篇博文主要介绍相关的内容,涉及到原型链和构造函数以及部分的实现,敬请期待 上篇博文中说到了Vue源码的目录结构是什么样的,每个目录的作用我们应该也有所了解。我们知道core/instance目录主要是用来实例化Vue对象,所以我...

    X_AirDu 评论0 收藏0
  • 人人都能懂的Vue源码系列—05—mergeOptions-上

    摘要:在解析完其构造函数上的之后,需要把构造函数上的和实例化时传入的进行合并操作并生成一个新的。检查组件名称是否合法首先看传入的三个参数,,这三个参数分别代表的是该实例构造函数上的实例化时传入的实例本身。 前几篇文章中我们讲到了resolveConstructorOptions,它的主要功能是解析当前实例构造函数上的options,不太明白的同学们可以看本系列的前几篇文章。在解析完其构造函数...

    iKcamp 评论0 收藏0
  • 人人都能懂的Vue源码系列—01—Vue源码目录结构

    摘要:阅读的源码,或者说阅读一个框架的源码,了解它的目录结构都是很有帮助的。人人都能懂的源码系列文章将会详细的介绍源码的方方面面。 阅读Vue的源码,或者说阅读一个框架的源码,了解它的目录结构都是很有帮助的。下面我们来看看Vue源码的目录结构。showImg(https://segmentfault.com/img/bV8fLS?w=598&h=654); Vue各目录简介 下图是Vue各个...

    MAX_zuo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<