摘要:果然我們找到了的構造函數定義。告訴你是一個構造函數,需要用操作符去調用。在深入方法之前,我們先把目光移到文件里在的構造函數定義之后,有一系列方法會被立即調用。下篇博文主要介紹相關的內容,涉及到原型鏈和構造函數以及部分的實現,敬請期待
上篇博文中說到了Vue源碼的目錄結構是什么樣的,每個目錄的作用我們應該也有所了解。我們知道core/instance目錄主要是用來實例化Vue對象,所以我們在這個目錄下面去尋找Vue構造函數。果然我們找到了Vue的構造函數定義。
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) }
當你新建一個Vue實例時候,會判斷如果當前的環境不是生產環境,且你在調用Vue的時候,沒有用new操作符。就會調用warn函數,拋出一個警告。告訴你Vue是一個構造函數,需要用new操作符去調用。這個warn函數不是單純的console.warn,它的實現我們后面的博文會介紹。
接下來,把options作為參數調用_init方法。options不做過多的介紹了,就是你調用new Vue時候傳入的參數。在深入_init方法之前,我們先把目光移到index.js文件里
function Vue (options) { ... } initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
在Vue的構造函數定義之后,有一系列方法會被立即調用。這些方法主要用來給Vue函數添加一些原型屬性和方法的。其中就有接下來要介紹的Vue.prototyoe._init
Vue.prototype._init在core/instance/init.js中我們找到了_init的定義。代碼已經做了一些中文注釋
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 // 有子組件時,options._isComponent才會為true if (options && options._isComponent) { // optimize internal component instantiation(實例) // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. // 優化組件實例,因為動態選項合并很慢,并且也沒有組件的選項需要特殊對待 // 優化components屬性 initInternalComponent(vm, options) } else { // 傳入的options和vue自身的options進行合并 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) // 初始化一些和生命周期相關的內容 initEvents(vm) // 初始化事件相關屬性,當有父組件的方法綁定在子組件時候,供子組件調用 initRender(vm) // 添加slot屬性 callHook(vm, "beforeCreate") // 調用beforeCreate鉤子 initState(vm) // 初始化數據,進行雙向綁定 state/props initProvide(vm) // resolve provide after data/props 注入provider的值到子組件中 callHook(vm, "created") // 調用created鉤子 /* istanbul ignore if */ // 計算覆蓋率時忽略下列代碼 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) // 把模板轉換成render函數 } }
我們逐一來分析上述代碼。首先緩存當前的上下文到vm變量中,方便之后調用。然后設置_uid屬性。_uid屬性是唯一的。當觸發init方法,新建Vue實例時(當渲染組件時也會觸發)uid都會遞增。
下面這段代碼主要是用來測試代碼性能的,在這個時候相當于打了一個"標記點"來測試性能。
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) }
對這部分內容感興趣的朋友們可以點擊我的另一篇文章Performance API查看。
接下來執行這行代碼vm._isVue = true,Vue的作者對這句話做了注釋。
an flag to avoid this being observed
乍看起來好像不太明白,好像是說為了防止this被observed實例化。那這究竟是什么意思呢?我們來看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時(即傳入的值是Vue實例本身)不會新建observer實例(這里可以暫時理解新建observer實例就是讓數據響應式)。
再回到init源碼部分
if (options && options._isComponent) { initInternalComponent(vm, options) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor), options || {}, vm ) }
當符合第一個條件是,即當前這個Vue實例是組件。則執行initInternalComponent方法。(該方法主要就是為vm.$options添加一些屬性, 后面講到組件的時候再詳細介紹)。當符合第二個條件時,即當前Vue實例不是組件。而是實例化Vue對象時,調用mergeOptions方法。mergeOptions主要調用兩個方法,resolveConstructorOptions和mergeOptions。這兩個方法牽涉到了很多知識點,為了我們文章篇幅的考慮。接下來準備通過兩篇博文來介紹這兩個方法。下篇博文主要介紹resolveConstructorOptions相關的內容,涉及到原型鏈和構造函數以及部分Vue.extend的實現,敬請期待!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94437.html
摘要:閱讀的源碼,或者說閱讀一個框架的源碼,了解它的目錄結構都是很有幫助的。人人都能懂的源碼系列文章將會詳細的介紹源碼的方方面面。 閱讀Vue的源碼,或者說閱讀一個框架的源碼,了解它的目錄結構都是很有幫助的。下面我們來看看Vue源碼的目錄結構。showImg(https://segmentfault.com/img/bV8fLS?w=598&h=654); Vue各目錄簡介 下圖是Vue各個...
摘要:上篇文章介紹了構造函數的部分實現,當前實例不是組件時,會執行方法。這個文件就是對構造函數進行的第一層包裝了。但是注意這里的代碼我們構造函數的第二層包裝,就在這個文件里了。回到的源碼中,當不存在時,直接返回基礎構造器的。 上篇文章介紹了Vue構造函數的部分實現,當前Vue實例不是組件時,會執行mergeOptions方法。 vm.$options = mergeOptions( re...
摘要:上一篇文章中說道,函數要分兩種情況進行說明,第一種是為基礎構造器的情況,這個已經向大家介紹過了,今天這篇文章主要介紹第二種情況,是創建的子類。表示的是當前構造器上新增的,表示的是當前構造器上新增的封裝。 上一篇文章中說道,resolveConstructorOptions函數要分兩種情況進行說明,第一種是Ctor為基礎構造器的情況,這個已經向大家介紹過了,今天這篇文章主要介紹第二種情況...
摘要:上一篇文章中說道,函數要分兩種情況進行說明,第一種是為基礎構造器的情況,這個已經向大家介紹過了,今天這篇文章主要介紹第二種情況,是創建的子類。表示的是當前構造器上新增的,表示的是當前構造器上新增的封裝。 上一篇文章中說道,resolveConstructorOptions函數要分兩種情況進行說明,第一種是Ctor為基礎構造器的情況,這個已經向大家介紹過了,今天這篇文章主要介紹第二種情況...
摘要:在解析完其構造函數上的之后,需要把構造函數上的和實例化時傳入的進行合并操作并生成一個新的。檢查組件名稱是否合法首先看傳入的三個參數,,這三個參數分別代表的是該實例構造函數上的實例化時傳入的實例本身。 前幾篇文章中我們講到了resolveConstructorOptions,它的主要功能是解析當前實例構造函數上的options,不太明白的同學們可以看本系列的前幾篇文章。在解析完其構造函數...
閱讀 2306·2021-11-23 10:09
閱讀 2885·2021-10-12 10:11
閱讀 2594·2021-09-29 09:35
閱讀 1336·2019-08-30 15:53
閱讀 2260·2019-08-30 11:15
閱讀 2904·2019-08-29 13:01
閱讀 2290·2019-08-28 18:15
閱讀 3363·2019-08-26 12:13