前言
這章其實(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)楹竺嫫涓父割?code>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)榫统鲈诟割惖淖兓衙浚运乃枷刖褪前雅袛喔割惖?code>options是否變化骨饿,變化了的話就把繼承下來(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)判斷是否是子類
若是是子類的話看看分支之內(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
首先獲取父類(Parent)
正確的options
,然后獲取執(zhí)行Child = Parent.extend()
時(shí)緩存的父類(Parent)
的options
峻汉。因?yàn)榍罢呤钱?dāng)前父類(Parent)
真實(shí)的options
贴汪,所以倆者可以通過(guò)比較來(lái)判斷之后是否改變過(guò)。
很明顯改過(guò)了(Vue.mixin({...})
導(dǎo)致Parent
繼承的值變了休吠,也就導(dǎo)致其真實(shí)的options
變了)
若是有改動(dòng)的話就先修正
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è)所謂的重呢就是是否和父類繼承過(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ù)組粉私,如果不是,那么就直接返回最新值近零,否則的話
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)的窖杀,也是新增的