vue源码解析:vue全局方法之Vue.extend实现原理

学习vue不得不学习vue实例上得方法,extend是一个组件继承vue实例得函数,我们就来看看Vue.extend函数得实现原理是什么?

用法:

Vue.extend( options )

参数

  • {Object} options

作用

使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。

data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数。

// 创建构造器
var Profile = Vue.extend({
  template: '

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

', data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } } }) // 创建 Profile 实例,并挂载到一个元素上。 new Profile().$mount('##mount-point')

 最后得结果是这样得:

Walter White aka Heisenberg

 原理:src/core/global-api/extend.js

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

    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
    }

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

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
}

以上是源码,从源码中可以看到,在最开始,声明了四个变量:

  • extendOptions:用户传入的一个包含组件选项的对象参数;
  • Super:指向父类,即基础 Vue类;
  • SuperId:父类的cid属性,无论是基础 Vue类还是从基础 Vue类继承而来的类,都有一个cid属性,作为该类的唯一标识;
  • cachedCtors:缓存池,用于缓存创建出来的类;

接着,在缓存池中先尝试获取之前已经创建过的该子类,如果之前创建过,则直接返回之前创建的。之所以有这一步,是因为Vue为了性能考虑,反复调用Vue.extend其实应该返回同一个结果,只要返回结果是固定的,就可以将结果缓存,再次调用时,只需从缓存中取出结果即可。在API方法定义的最后,当创建完子类后,会使用父类的cid作为key,创建好的子类作为value,存入缓存池cachedCtors中。

紧接着,从传入的组件选项参数对象中获取name字段,并且如果是生成环境,就去校验这个name是否合法。

然后创建了一个Sub的类,用来继承Vue基础类的子类。所以类里面执行了init函数,初始化事件,state,等(声明周期中的init函数)。

所以,现在创建好了子类,并且继承了vue基础类的属性。具备了vue类的功能。

那么接下来就是将父类的原型继承到子类中,并且为子类添加上唯一的cid标识。然后将父类的options和子类的options进行合并,将结果赋给子类的options。紧接着将父类保存到子类的super中,这样保证能在子类中获取到父类。

接下来是对props的处理,如果在options中存在props,那么就初始化props,如果options中存在computed属性,那么同样初始化computed。

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, computed[key])
  }
}

初始化props属性就是遍历参数中传入的computed选项,将每一项都调用defineComputed函数定义到子类原型上。此处的defineComputed函数与我们之前在生命周期初始化阶段initState中所介绍的defineComputed函数是一样的。

然后将父类复制到子类中去。给子类新增三个属性。最后,使用父类的cid作为key,创建好的子类Sub作为value,存入缓存池cachedCtors中。

最终将创建好的子类Sub返回。

以上,就是Vue.extend的所有逻辑。其实总体来讲,整个过程就是先创建一个类Sub,接着通过原型继承的方式将该类继承基础Vue类,然后给Sub类添加一些属性以及将父类的某些属性复制到Sub类上,最后将Sub类返回。

你可能感兴趣的:(Vue)