上一篇文章中說道,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中屬於比較核心的一個方法。敬請期待!