源码分析(含代码注释) Vue.extend

extend

官方的定义是:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
话不多说,上源码:

export function initExtend (Vue: GlobalAPI) {
  /**
   * Each instance constructor, including Vue, has a unique
   * cid. This enables us to create wrapped "child
   * constructors" for prototypal inheritance and cache them.
   */
  Vue.cid = 0
  let cid = 1

  /**
   * Class inheritance
   */
  Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    
    const SuperId = Super.cid // id作为唯一标识符用作缓存
    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)
    }
    // 继承Vue的原型对象
    Sub.prototype = Object.create(Super.prototype)
    // consturctor指向自身
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    // 合并配置 将Vue上面的配置与传入的对象配置 合并
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    // 添加super属性指向Super
    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.
    // 对于props和computed属性,我们在扩展时在扩展原型的Vue实例上定义代理getter。 
    // 这样可以避免对创建的每个实例调用Object.defineProperty。
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage 
    // 扩展API
    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
  }
}

这个方法其实就是基于构造函数Vue,创建了一个VueComponent子构造器。
首先将Vue赋值给Super,Vue的id赋值给SuperId,创建了一个缓存对象cachedCtors(这儿的作用是防止多次创建同一个构造器),
接下来获取name,并校验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

下一步是创建了一个子构造函数,将子构造函数的原型指向Vue构造函数的原型对象,继承Vue的一些能力,再将子构造函数指向自身。
下一步是mergeOptions,这儿的作用是将Vue的一些配置项与我们传入的配置项(也就是传入的对象)执行一些合并策略,进行配置项合并,这样Vue上定义的一些配置项,在子构造器中也会存在了.。
接着添加了super属性指向了构造函数Vue。

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

function initProps(Comp) {
	const props = Comp.options.props
	for(const key in props ) {
		proxy(Comp.prototype, `_props`, key)
	}
}

function initComputed(Comp) {
	const computed = Comp.options.computed
	for(const key in computed) {
		defineComputed(Comp.prototype, key, compted[key])
	}
}

接下来,对合并后的props和computed进行初始化。
这儿对props做了一层代理,以方便我们可以通过this.key访问到props里面的属性。
difineComputed也是初始化了computed,给computed属性添加了getter和setter,这个涉及响应式,后面的文章我们会分析。

// 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
    }
	
	export const ASSET_TYPES = [
		'component',
		'directive',
		'filter'
	]

完成props与computed初始化后,再继续将Vue的一些原生API(extend、mixin、use、component、directive、filter)等扩展到子构造器上面

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

完成了对Vue这些能力的继承和扩展后,再将Vue的option、自身扩展的option等存放到子构造器相应的属性上,最后将子构造器缓存到缓存数组里面,返回新构建的构造器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值