摘要:果然我們找到了的構(gòu)造函數(shù)定義。告訴你是一個(gè)構(gòu)造函數(shù),需要用操作符去調(diào)用。在深入方法之前,我們先把目光移到文件里在的構(gòu)造函數(shù)定義之后,有一系列方法會(huì)被立即調(diào)用。下篇博文主要介紹相關(guān)的內(nèi)容,涉及到原型鏈和構(gòu)造函數(shù)以及部分的實(shí)現(xiàn),敬請(qǐng)期待
上篇博文中說到了Vue源碼的目錄結(jié)構(gòu)是什么樣的,每個(gè)目錄的作用我們應(yīng)該也有所了解。我們知道core/instance目錄主要是用來實(shí)例化Vue對(duì)象,所以我們?cè)谶@個(gè)目錄下面去尋找Vue構(gòu)造函數(shù)。果然我們找到了Vue的構(gòu)造函數(shù)定義。
function Vue (options) { if (process.env.NODE_ENV !== "production" && !(this instanceof Vue) ) { warn("Vue is a constructor and should be called with the `new` keyword") } this._init(options) }
當(dāng)你新建一個(gè)Vue實(shí)例時(shí)候,會(huì)判斷如果當(dāng)前的環(huán)境不是生產(chǎn)環(huán)境,且你在調(diào)用Vue的時(shí)候,沒有用new操作符。就會(huì)調(diào)用warn函數(shù),拋出一個(gè)警告。告訴你Vue是一個(gè)構(gòu)造函數(shù),需要用new操作符去調(diào)用。這個(gè)warn函數(shù)不是單純的console.warn,它的實(shí)現(xiàn)我們后面的博文會(huì)介紹。
接下來,把options作為參數(shù)調(diào)用_init方法。options不做過多的介紹了,就是你調(diào)用new Vue時(shí)候傳入的參數(shù)。在深入_init方法之前,我們先把目光移到index.js文件里
function Vue (options) { ... } initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
在Vue的構(gòu)造函數(shù)定義之后,有一系列方法會(huì)被立即調(diào)用。這些方法主要用來給Vue函數(shù)添加一些原型屬性和方法的。其中就有接下來要介紹的Vue.prototyoe._init
Vue.prototype._init在core/instance/init.js中我們找到了_init的定義。代碼已經(jīng)做了一些中文注釋
Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid vm._uid = uid++ let startTag, endTag /* istanbul ignore if */ if (process.env.NODE_ENV !== "production" && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) } // a flag to avoid this being observed vm._isVue = true // merge options // 有子組件時(shí),options._isComponent才會(huì)為true if (options && options._isComponent) { // optimize internal component instantiation(實(shí)例) // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. // 優(yōu)化組件實(shí)例,因?yàn)閯?dòng)態(tài)選項(xiàng)合并很慢,并且也沒有組件的選項(xiàng)需要特殊對(duì)待 // 優(yōu)化components屬性 initInternalComponent(vm, options) } else { // 傳入的options和vue自身的options進(jìn)行合并 vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) } /* istanbul ignore else */ if (process.env.NODE_ENV !== "production") { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm initLifecycle(vm) // 初始化一些和生命周期相關(guān)的內(nèi)容 initEvents(vm) // 初始化事件相關(guān)屬性,當(dāng)有父組件的方法綁定在子組件時(shí)候,供子組件調(diào)用 initRender(vm) // 添加slot屬性 callHook(vm, "beforeCreate") // 調(diào)用beforeCreate鉤子 initState(vm) // 初始化數(shù)據(jù),進(jìn)行雙向綁定 state/props initProvide(vm) // resolve provide after data/props 注入provider的值到子組件中 callHook(vm, "created") // 調(diào)用created鉤子 /* istanbul ignore if */ // 計(jì)算覆蓋率時(shí)忽略下列代碼 if (process.env.NODE_ENV !== "production" && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) } if (vm.$options.el) { vm.$mount(vm.$options.el) // 把模板轉(zhuǎn)換成render函數(shù) } }
我們逐一來分析上述代碼。首先緩存當(dāng)前的上下文到vm變量中,方便之后調(diào)用。然后設(shè)置_uid屬性。_uid屬性是唯一的。當(dāng)觸發(fā)init方法,新建Vue實(shí)例時(shí)(當(dāng)渲染組件時(shí)也會(huì)觸發(fā))uid都會(huì)遞增。
下面這段代碼主要是用來測試代碼性能的,在這個(gè)時(shí)候相當(dāng)于打了一個(gè)"標(biāo)記點(diǎn)"來測試性能。
let startTag, endTag /* istanbul ignore if */ process.env.NODE_ENV === "develop" if (process.env.NODE_ENV !== "production" && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) }
對(duì)這部分內(nèi)容感興趣的朋友們可以點(diǎn)擊我的另一篇文章Performance API查看。
接下來執(zhí)行這行代碼vm._isVue = true,Vue的作者對(duì)這句話做了注釋。
an flag to avoid this being observed
乍看起來好像不太明白,好像是說為了防止this被observed實(shí)例化。那這究竟是什么意思呢?我們來看observer的代碼。
export function observe (value: any, asRootData: ?boolean): Observer | void { ... else if ( observerState.shouldConvert && !isServerRendering() && (Array.isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue ) { ob = new Observer(value) } ... }
如果傳入值的_isVue為ture時(shí)(即傳入的值是Vue實(shí)例本身)不會(huì)新建observer實(shí)例(這里可以暫時(shí)理解新建observer實(shí)例就是讓數(shù)據(jù)響應(yīng)式)。
再回到init源碼部分
if (options && options._isComponent) { initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) }
當(dāng)符合第一個(gè)條件是,即當(dāng)前這個(gè)Vue實(shí)例是組件。則執(zhí)行initInternalComponent方法。(該方法主要就是為vm.$options添加一些屬性, 后面講到組件的時(shí)候再詳細(xì)介紹)。當(dāng)符合第二個(gè)條件時(shí),即當(dāng)前Vue實(shí)例不是組件。而是實(shí)例化Vue對(duì)象時(shí),調(diào)用mergeOptions方法。mergeOptions主要調(diào)用兩個(gè)方法,resolveConstructorOptions和mergeOptions。這兩個(gè)方法牽涉到了很多知識(shí)點(diǎn),為了我們文章篇幅的考慮。接下來準(zhǔn)備通過兩篇博文來介紹這兩個(gè)方法。下篇博文主要介紹resolveConstructorOptions相關(guān)的內(nèi)容,涉及到原型鏈和構(gòu)造函數(shù)以及部分Vue.extend的實(shí)現(xiàn),敬請(qǐng)期待!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94437.html
摘要:閱讀的源碼,或者說閱讀一個(gè)框架的源碼,了解它的目錄結(jié)構(gòu)都是很有幫助的。人人都能懂的源碼系列文章將會(huì)詳細(xì)的介紹源碼的方方面面。 閱讀Vue的源碼,或者說閱讀一個(gè)框架的源碼,了解它的目錄結(jié)構(gòu)都是很有幫助的。下面我們來看看Vue源碼的目錄結(jié)構(gòu)。showImg(https://segmentfault.com/img/bV8fLS?w=598&h=654); Vue各目錄簡介 下圖是Vue各個(gè)...
摘要:上篇文章介紹了構(gòu)造函數(shù)的部分實(shí)現(xiàn),當(dāng)前實(shí)例不是組件時(shí),會(huì)執(zhí)行方法。這個(gè)文件就是對(duì)構(gòu)造函數(shù)進(jìn)行的第一層包裝了。但是注意這里的代碼我們構(gòu)造函數(shù)的第二層包裝,就在這個(gè)文件里了?;氐降脑创a中,當(dāng)不存在時(shí),直接返回基礎(chǔ)構(gòu)造器的。 上篇文章介紹了Vue構(gòu)造函數(shù)的部分實(shí)現(xiàn),當(dāng)前Vue實(shí)例不是組件時(shí),會(huì)執(zhí)行mergeOptions方法。 vm.$options = mergeOptions( re...
摘要:上一篇文章中說道,函數(shù)要分兩種情況進(jìn)行說明,第一種是為基礎(chǔ)構(gòu)造器的情況,這個(gè)已經(jīng)向大家介紹過了,今天這篇文章主要介紹第二種情況,是創(chuàng)建的子類。表示的是當(dāng)前構(gòu)造器上新增的,表示的是當(dāng)前構(gòu)造器上新增的封裝。 上一篇文章中說道,resolveConstructorOptions函數(shù)要分兩種情況進(jìn)行說明,第一種是Ctor為基礎(chǔ)構(gòu)造器的情況,這個(gè)已經(jīng)向大家介紹過了,今天這篇文章主要介紹第二種情況...
摘要:上一篇文章中說道,函數(shù)要分兩種情況進(jìn)行說明,第一種是為基礎(chǔ)構(gòu)造器的情況,這個(gè)已經(jīng)向大家介紹過了,今天這篇文章主要介紹第二種情況,是創(chuàng)建的子類。表示的是當(dāng)前構(gòu)造器上新增的,表示的是當(dāng)前構(gòu)造器上新增的封裝。 上一篇文章中說道,resolveConstructorOptions函數(shù)要分兩種情況進(jìn)行說明,第一種是Ctor為基礎(chǔ)構(gòu)造器的情況,這個(gè)已經(jīng)向大家介紹過了,今天這篇文章主要介紹第二種情況...
摘要:在解析完其構(gòu)造函數(shù)上的之后,需要把構(gòu)造函數(shù)上的和實(shí)例化時(shí)傳入的進(jìn)行合并操作并生成一個(gè)新的。檢查組件名稱是否合法首先看傳入的三個(gè)參數(shù),,這三個(gè)參數(shù)分別代表的是該實(shí)例構(gòu)造函數(shù)上的實(shí)例化時(shí)傳入的實(shí)例本身。 前幾篇文章中我們講到了resolveConstructorOptions,它的主要功能是解析當(dāng)前實(shí)例構(gòu)造函數(shù)上的options,不太明白的同學(xué)們可以看本系列的前幾篇文章。在解析完其構(gòu)造函數(shù)...
閱讀 2341·2021-11-23 10:09
閱讀 2904·2021-10-12 10:11
閱讀 2608·2021-09-29 09:35
閱讀 1353·2019-08-30 15:53
閱讀 2276·2019-08-30 11:15
閱讀 2922·2019-08-29 13:01
閱讀 2305·2019-08-28 18:15
閱讀 3376·2019-08-26 12:13