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等存放到子构造器相应的属性上,最后将子构造器缓存到缓存数组里面,返回新构建的构造器。