Vue.extend是用来创造Vue子类的。说是子类,但是一般都能完成特殊功能,后面要讲的组件其实就是特殊的Vue子类。一般而言很少需要我们自己调用Vue.exend方法,生成组件子类是自动完成的,element-ui的message功能手动调用了Vue.extend方法创造了一个子类。

Vue.extend = function (extendOptions: Object): Function {
  extendOptions = extendOptions || {}
  const Super = this
  // 父类id
  const SuperId = Super.cid

  // cachedCtors用来缓存创造的子类
  // 同一个extendOptions同一个父类只会生成一个子类
  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') {
    if (!/^[a-zA-Z][\w-]*$/.test(name)) {
      warn(
        'Invalid component name: "' + name + '". Component names ' +
        'can only contain alphanumeric characters and the hyphen, ' +
        'and must start with a letter.'
      )
    }
  }

  // 子类构造函数
  const Sub = function VueComponent (options) {
    this._init(options)
  }

  // 继承父类的prototype
  Sub.prototype = Object.create(Super.prototype)

  // 子类的原型对象的constructor指回子类
  // 其实是屏蔽掉父类原型对象的constructor属性
  Sub.prototype.constructor = Sub

  // 子类id
  Sub.cid = cid++

  // 合并父类的options和子类的options
  Sub.options = mergeOptions(
    Super.options,
    extendOptions
  )
  Sub['super'] = Super


  // 定义的props代理到原型对象上
  // 实例初始化props时只需代理自身特有的props
  if (Sub.options.props) {
    initProps(Sub)
  }

  // 和上面类似,把公有的computed代理到原型对象上
  // 实例初始化computed时只需代理自身特有computed
  if (Sub.options.computed) {
    initComputed(Sub)
  }

  // 复制静态方法
  Sub.extend = Super.extend
  Sub.mixin = Super.mixin
  Sub.use = Super.use


  // 依然是静态方法的复制
  // component、directive、filter
  ASSET_TYPES.forEach(function (type) {
    Sub[type] = Super[type]
  })

  // 如果有名,把该子类当成一个组件注册
  if (name) {
    Sub.options.components[name] = Sub
  }

  Sub.superOptions = Super.options
  Sub.extendOptions = extendOptions
  Sub.sealedOptions = extend({}, Sub.options)

  // 缓存子类
  cachedCtors[SuperId] = Sub

  return Sub
}

// 公有的props代理到prototype上
function initProps (Comp) {
  const props = Comp.options.props
  for (const key in props) {
    proxy(Comp.prototype, `_props`, key)
  }
}

// 公有的computed的代理到prototype上
function initComputed (Comp) {
  const computed = Comp.options.computed
  for (const key in computed) {
    defineComputed(Comp.prototype, key, computed[key])
  }
}

如果熟悉javascript的继承上面代码就比较好理解了,静态方法就直接复制粘贴了,原定对象上继承使用了Object.create方法。还有要说的是关于props和computed,直接代理到了原型对象上,子类的实例在初始化时就不用重复代理了。

results matching ""

    No results matching ""