從入口代碼開始分析,我們先來分析 new Vue 背后發生了哪些事情。我們都知道,new 關鍵字在 Javascript 語言中代表實例化是一個對象,而 Vue 實際上是一個類,類在 Javascript 中是用 Function 來實現的,來看一下源碼,在src/core/instance/index.js 中。
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 只能通過 new 關鍵字初始化,然后會調用 this._init 方法, 該方法在 src/core/instance/init.js 中定義。
Vue.prototype._init = function (options?: Object) {const vm: Component = thisvm._uid = uid++let startTag, endTagif (process.env.NODE_ENV !== 'production' && config.performance && mark) {startTag = `vue-perf-start:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)}vm._isVue = trueif (options && options._isComponent) {initInternalComponent(vm, options)} else {vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}if (process.env.NODE_ENV !== 'production') {initProxy(vm)} else {vm._renderProxy = vm}vm._self = vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm)initState(vm)initProvide(vm)callHook(vm, 'created')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)}
}
Vue 初始化主要就干了幾件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。
總結
Vue 的初始化邏輯寫的非常清楚,把不同的功能邏輯拆成一些單獨的函數執行,讓主線邏輯一目了然,這樣的編程思想是非常值得借鑒和學習的。
由于我們這一章的目標是弄清楚模板和數據如何渲染成最終的 DOM,所以各種初始化邏輯我們先不看。在初始化的最后,檢測到如果有 el 屬性,則調用 vm.$mount 方法掛載 vm,掛載的目標就是把模板渲染成最終的 DOM,那么接下來我們來分析 Vue 的掛載過程。