上一篇文章中说道,resolveConstructorOptions函数要分两种状况进行说明,第一种是Ctor为基础构造器的状况,这个已经向你们介绍过了,今天这篇文章主要介绍第二种状况,Ctor是Vue.extend建立的"子类"。数组
Vue.extend方法咱们以后的博文再进行详细介绍,这里你们能够先把Vue.extend的功能笼统的理解为继承。咱们接下来看resolveConstructorOptions相关的代码,若是Ctor是Vue.extend建立的"子类",那么在extend的过程当中,Ctor上就会有super属性。函数
Vue.extend = function (extendOptions: Object): Function { ... Sub['super'] = Super ... }
Ctor上有了super属性,就会去执行if块内的代码spa
... const superOptions = resolveConstructorOptions(Ctor.super) const cachedSuperOptions = Ctor.superOptions ... // Vue.extend相关代码 Vue.extend = function (extendOptions: Object): Function { ... Sub.superOptions = Super.options // Sub.superOptions指向基础构造器的options ... }
首先递归调用resolveConstructorOptions方法,返回"父类"上的options并赋值给superOptions变量。而后把"自身"的options赋值给cachedSuperOptions变量。
而后比较这两个变量的值,当这两个变量值不等时,说明"父类"的options改变过了。例如执行了Vue.mixin方法,这时候就须要把"自身"的superOptions属性替换成最新的。而后检查是否"自身"d的options是否发生变化。resolveModifiedOptions的功能就是这个。3d
if (superOptions !== cachedSuperOptions) { // super option changed, // need to resolve new options. Ctor.superOptions = superOptions // check if there are any late-modified/attached options (#4976) const modifiedOptions = resolveModifiedOptions(Ctor) .... }
说了这么多,你们可能仍是有点陌生,咱们直接举个例子来讲明一下。code
var Profile = Vue.extend({ template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>' }) Vue.mixin({ data: function () { return { firstName: 'Walter', lastName: 'White', alias: 'Heisenberg' } }}) new Profile().$mount('#example')
因为Vue.mixin改变了"父类"options。源码中superOptions和cachedSuperOptions就不相等了,你们能够去jsfiddle试试效果。
接下来看看resolveModifiedOptions都干了哪些事情?component
function resolveModifiedOptions (Ctor: Class<Component>): ?Object { let modified // 定义modified变量 const latest = Ctor.options // 自身的options const extended = Ctor.extendOptions // 构造"自身"时传入的options const sealed = Ctor.sealedOptions // 执行Vue.extend时封装的"自身"options,这个属性就是方便检查"自身"的options有没有变化 // 遍历当前构造器上的options属性,若是在"自身"封装的options里没有,则证实是新添加的。执行if内的语句。调用dedupe方法,最终返回modified变量(即”自身新添加的options“) for (const key in latest) { if (latest[key] !== sealed[key]) { if (!modified) modified = {} modified[key] = dedupe(latest[key], extended[key], sealed[key]) } } return modified }
那么dedupe方法又干了什么事情呢?blog
function dedupe (latest, extended, sealed) { // compare latest and sealed to ensure lifecycle hooks won't be duplicated // between merges if (Array.isArray(latest)) { const res = [] sealed = Array.isArray(sealed) ? sealed : [sealed] extended = Array.isArray(extended) ? extended : [extended] for (let i = 0; i < latest.length; i++) { // push original options and not sealed options to exclude duplicated options if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) { res.push(latest[i]) } } return res } else { return latest } }
从做者的注释能够看到这个方法主要就是防止生命周期构造函数重复。咱们再来看该方法传入的3个参数。latest,extended,sealed,lateset表示的是"自身"新增的options。extended表示的是当前构造器上新增的extended options,sealed表示的是当前构造器上新增的封装options。
回到源码,若是latest不是数组的话(lateset是"自身"新增的options),这里不须要去重,直接返回latest。若是传入的latest是数组(若是latest是数组,通常这个新增的options就是生命周期钩子函数),则遍历该数组,若是该数组的某项在extended数组中有或者在sealed数组中没有,则推送到返回数组中从而实现去重。(这个去重逻辑目前本身还不是特别明白,以后若是明白了会在这里更新,有明白的同窗们请在评论区留言)
如今咱们了解了resolveModifiedOptions和dedupe方法的做用,接下来回到resolveConstructorOptions源码。继承
if (modifiedOptions) { extend(Ctor.extendOptions, modifiedOptions) } options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions) if (options.name) { options.components[options.name] = Ctor }
若是”自身“有新添加的options,则把新添加的options属性添加到Ctor.extendOptions属性上。调用mergeOptions方法合并"父类"构造器上的options和”自身“上的extendOptions(mergeOptions在下一篇博文中介绍),最后返回合并后的options。递归
看到这里,可能会感受到头晕,为了让你们更好的理解。咱们来看下面的流程图。生命周期
下篇博客咱们主要讲mergeOptions方法,在整个Vue中属于比较核心的一个方法。敬请期待!