Skip to content

12 - 组件化 (createComponent 的实现) - part 3 #12

@chenfaxiang

Description

@chenfaxiang

createComponent —— 构造子类构造函数

从前面的part 2学习部分了解到在构造子类构造函数的时候执行的代码是:

const baseCtor = context.$options._base

  // plain options object: turn it into a constructor
  // 构造子类构造函数
  if (isObject(Ctor)) {
    // 这里 baseCtor.extend 就等价于 Vue.extend()
    // extend() 方法在哪里定义的?主要逻辑是干什么?
    // /src/core/global-api/extend.js 文件中定义了方法 Vue.extend()
    Ctor = baseCtor.extend(Ctor)
  }

这里发现 baseCotr是在 /src/core/global-api/index.js 初始化函数 initGlobalAPI 中定义的:

Vue.options._base = Vue

在实例构造函数的过程中把 options 合并进了 $options 中,其在 /src/core/instance/init.js 定义 _init 方法的时候有这样一个操作:

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

到这里,可以看到 $optionsbaseCtor 已经弄清楚是怎么进行的定义甚至了解了对应的功能作用,那么回到 baseCtor.extend(Ctor) 语句,这里等价于 Vue.extend(Ctor) ,而 extend() 方法又是在哪里定义,究竟是干什么的呢?

// /src/core/global-api/extend.js
  /**
   * Class inheritance
   * extend 方法的作用就是构造一个子类
   */
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    // 利用原型继承构建子类
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor 缓存一波
    cachedCtors[SuperId] = Sub
    return Sub
  }
}

在文件 /src/core/global-api/extend.js 中定义了方法 Vue.extend = function(){} ,其中使用了经典的原型链继承将一个纯对象转换成了一个继承于 Vue 的构造器 Sub 并返回,还对 Sub 对象进行了各种扩展属性的添加;
通过上面的学习认知发现,在构造子构造函数的过程中是通过 Vue.extend() 方法利用原型链继承进行了构造,最终返回一个结果。差不多了,下一节接续。。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions