前言
這章其實(shí)只講src/core/instance/init.js里的resolveConstructorOptions函數(shù)。
這個(gè)函數(shù)水有點(diǎn)深,網(wǎng)上的很多文章都沒(méi)說(shuō)全,所以單獨(dú)拎出來(lái)
正文
首先來(lái)個(gè)栗子
const fn1 = function fn1() {
console.log('fn1')
}
const fn2 = function fn2() {
console.log('fn2')
}
const fn3 = function fn3() {
console.log('fn3')
}
const fn4 = function fn4() {
console.log('fn4')
}
const Parent = Vue.extend({
template: '<p>1</p>',
created: [fn1]
})
const Child = Parent.extend({
name: 'Child',
template: '<p>2</p>',
created: [fn2]
})
Vue.mixin({
template: '<p>3</p>',
created: [fn3]
})
Child.mixin({
template: '<p>4</p>',
created: [fn4]
})
new Child({}).$mount('#app')
當(dāng)我們計(jì)算Child的options的時(shí)候我們不能簡(jiǎn)單的取Child.options,因?yàn)楹竺嫫涓父割?lèi)Vue混入了options,其本身也混入了options。這時(shí)候我們?nèi)〉?code>Child.options會(huì)漏了Vue.mixin混入的options。
這也是很好理解,因?yàn)?code>Child.options在Child = Parent.extend()之后除了Child.mixin()就沒(méi)改過(guò),但是Vue.mixin()導(dǎo)致Vue.options改變了,所以本該繼承下來(lái)的沒(méi)繼承
resolveConstructorOptions就是為了解決這個(gè)問(wèn)題,因?yàn)榫统鲈诟割?lèi)的變化,所以它的思想就是把判斷父類(lèi)的options是否變化,變化了的話(huà)就把繼承下來(lái)的和.extend、.mixin擴(kuò)展的區(qū)分開(kāi)來(lái),后者算新增的,前者是繼承的。倆者合并就是新的options
resolveConstructorOptions
就像標(biāo)題所述,這個(gè)是解析傳入的構(gòu)造函數(shù)的options,然后返回新的options(內(nèi)部會(huì)修正一些變量)
首先我們假設(shè)下面的Ctor是在Child的時(shí)候的情況對(duì)于上文的栗子而言
export function resolveConstructorOptions(Ctor: Class < Component > ) {
let options = Ctor.options
if (Ctor.super) {
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
if (superOptions !== cachedSuperOptions) {
Ctor.superOptions = superOptions
const modifiedOptions = resolveModifiedOptions(Ctor)
if (modifiedOptions) {
extend(Ctor.extendOptions, modifiedOptions)
}
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
options.components[options.name] = Ctor
}
}
}
return options
}
首先根據(jù)是否有super屬性來(lái)判斷是否是子類(lèi)
若是是子類(lèi)的話(huà)看看分支之內(nèi)
/**
{
components: {},
directives: {},
filters: {},
_base: function () {},
template: "<p>1</p>",
created: [fn3, fn1]
}
*/
const superOptions = resolveConstructorOptions(Ctor.super)
/**
{
components: {},
directives: {},
filters: {},
_base: function () {},
template: "<p>1</p>",
created: [fn1]
}
*/
const cachedSuperOptions = Ctor.superOptions
首先獲取父類(lèi)(Parent)正確的options,然后獲取執(zhí)行Child = Parent.extend()時(shí)緩存的父類(lèi)(Parent)的options。因?yàn)榍罢呤钱?dāng)前父類(lèi)(Parent)真實(shí)的options,所以倆者可以通過(guò)比較來(lái)判斷之后是否改變過(guò)。
很明顯改過(guò)了(Vue.mixin({...})導(dǎo)致Parent繼承的值變了,也就導(dǎo)致其真實(shí)的options變了)
若是有改動(dòng)的話(huà)就先修正
Ctor.superOptions = superOptions
然后到重要的點(diǎn)
const modifiedOptions = resolveModifiedOptions(Ctor)
就是它,解析新增的那部分options
resolveModifiedOptions
這個(gè)就是上面所說(shuō)的獲取通過(guò).extend、.mixin新增的那部分options
function resolveModifiedOptions(Ctor: Class < Component > ): ? Object {
let modified
/**
{
components: {},
directives: {},
filters: {},
_base: function () {},
template: "<p4</p>",
created: [fn1, fn2, fn4]
}
*/
const latest = Ctor.options
// { template: '<p>2</p>', created: [fn2] }
const extended = Ctor.extendOptions
/**
{
components: {},
directives: {},
filters: {},
_base: function () {},
template: "<p>2</p>",
created: [fn1, fn2]
}
*/
const sealed = Ctor.sealedOptions
for (const key in latest) {
if (latest[key] !== sealed[key]) {
if (!modified) modified = {}
modified[key] = dedupe(latest[key], extended[key], sealed[key])
}
}
return modified
}
首先獲取三個(gè)屬性,我們單看created
-
latest最新的options。首先fn1是Parent繼承而來(lái),fn2是生成自身時(shí)傳入的參數(shù),fn4是Child.mixin混入的,至于fn3是Vue上,相對(duì)Child是祖父,不過(guò)因?yàn)槭?code>Parent生成之后才混入,所以就沒(méi)繼承到,所以需要修正 -
extended執(zhí)行.extend傳入的的options參數(shù)。這個(gè)很簡(jiǎn)單,就是生成Child時(shí).extend傳入的參數(shù),也就是只有fn2 -
sealed執(zhí)行.extend時(shí)options的數(shù)據(jù)副本(若是之后有變動(dòng),那么這個(gè)值將和.options的值不一樣)。這個(gè)也簡(jiǎn)單,就是生成Child時(shí)Child.options的數(shù)據(jù)副本(也就是之后只要沒(méi)修正都不會(huì)變動(dòng),所以叫sealed)。fn1是Parent繼承而來(lái),fn2是生成自身時(shí)傳入的參數(shù)
然后遍歷latest,要是值有了變化
if (latest[key] !== sealed[key]) {
if (!modified) modified = {}
modified[key] = dedupe(latest[key], extended[key], sealed[key])
}
那么就得判斷這個(gè)值是否有重復(fù)(數(shù)組情況,比如生命周期鉤子),這個(gè)所謂的重呢就是是否和父類(lèi)繼承過(guò)來(lái)的那部分重復(fù)了。很明顯,這里的fn1就重了,因?yàn)槭?code>Parent繼承來(lái)的
dedupe
去重函數(shù)
function dedupe(latest, extended, sealed) {
if (Array.isArray(latest)) {
...
} else {
return latest
}
}
首先判斷傳入的當(dāng)前值是不是數(shù)組,如果不是,那么就直接返回最新值,否則的話(huà)
const res = []
// [fn1, fn2]
sealed = Array.isArray(sealed) ? sealed : [sealed]
// [fn2]
extended = Array.isArray(extended) ? extended : [extended]
for (let i = 0; i < latest.length; i++) {
if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) {
res.push(latest[i])
}
}
// [fn2, fn4]
return res
我們可見(jiàn)首先規(guī)范化倆參數(shù)為數(shù)組,然后遍歷最新值,這里這個(gè)if語(yǔ)句有點(diǎn)難理解
其實(shí)他走的倆策略
- 若是通過(guò)
.extend傳入的那么就不是繼承來(lái)的 - 若不在
sealed,那么必然是.extend之后改動(dòng)的,也是新增的