當你調用?new Vue()
?時,Vue.js 會執行一系列復雜的初始化過程。讓我們深入剖析這個看似簡單的操作背后發生的事情:
1. 初始化階段
(1) 內部初始化
function Vue(options) {if (!(this instanceof Vue)) {warn('Vue is a constructor and should be called with the `new` keyword');}this._init(options); // 關鍵初始化入口
}
(2) 合并選項
-
合并構造函數選項 (
Vue.options
) 和實例選項 (new Vue
?傳入的選項) -
處理?
components
,?directives
,?filters
?等 -
生命周期鉤子:合并為數組形式(混入時多個鉤子都會執行)
-
data:必須為函數,合并后調用函數返回新對象
-
自定義合并:可通過?
Vue.config.optionMergeStrategies
?定制
// 示例:自定義選項合并策略
Vue.config.optionMergeStrategies.customOption = function (parentVal, childVal) {return childVal === undefined ? parentVal : childVal;
};
2. 核心初始化流程
(1) 生命周期開始
callHook(vm, 'beforeCreate')
(2) 響應式系統建立
initInjections(vm) // 處理注入
initState(vm) // 核心響應式處理
initProvide(vm) // 處理提供
其中?initState
?包含:
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) initData(vm)
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch) initWatch(vm, opts.watch)
(3) 掛載準備
callHook(vm, 'created')if (vm.$options.el) {vm.$mount(vm.$options.el) // 觸發掛載
}
3. 響應式系統深度解析
數據觀測實現
function initData(vm) {let data = vm.$options.data;data = vm._data = typeof data === 'function' ? getData(data, vm): data || {};// 數據代理:vm.xxx -> vm._data.xxxproxy(vm, '_data', key);// 核心響應式處理observe(data);
}
依賴收集原理
class Observer {constructor(value) {this.value = value;this.dep = new Dep();if (Array.isArray(value)) {// 數組的特殊處理protoAugment(value, arrayMethods);this.observeArray(value);} else {// 對象的處理this.walk(value);}}walk(obj) {Object.keys(obj).forEach(key => {defineReactive(obj, key, obj[key]);});}
}
4. 依賴收集的完整閉環
function defineReactive(obj, key, val) {const dep = new Dep();let childOb = observe(val); // 遞歸觀察子屬性Object.defineProperty(obj, key, {get() {if (Dep.target) {dep.depend(); // 收集依賴if (childOb) {childOb.dep.depend(); // 子對象依賴收集if (Array.isArray(val)) {dependArray(val); // 數組元素依賴收集}}}return val;},set(newVal) {if (newVal === val) return;val = newVal;childOb = observe(newVal); // 新值觀察dep.notify(); // 觸發更新}});
}
5. 虛擬DOM與渲染系統
在?$mount
?階段:
Vue.prototype.$mount = function(el) {el = el && query(el);// 防止重復掛載if (el === document.body || el === document.documentElement) {warn("Do not mount Vue to <html> or <body>");return this;}const options = this.$options;// 解析模板/el到render函數if (!options.render) {let template = options.template;if (template) {// 處理各種模板來源} else if (el) {template = getOuterHTML(el);}if (template) {// 編譯核心流程const { render, staticRenderFns } = compileToFunctions(template,{ ... },this);options.render = render;options.staticRenderFns = staticRenderFns;}}// 調用真正的掛載方法return mount.call(this, el);
};
5. 完整生命周期圖示
new Vue()
│
├─ beforeCreate
│ ├─ 初始化事件/生命周期
│ └─ 未初始化響應式數據
│
├─ created
│ ├─ 已完成響應式觀測
│ ├─ 計算屬性/methods/watch已配置
│ └─ 未掛載DOM
│
├─ beforeMount
│ ├─ 編譯模板為render函數
│ └─ 未執行DOM掛載
│
├─ mounted
│ ├─ 已完成DOM掛載
│ └─ $el可用
│
├─ beforeUpdate (數據變化時)
│
├─ updated
│
├─ beforeDestroy
│
└─ destroyed
6. 性能優化相關設計
-
異步更新隊列:
// 變更檢測是異步的 Vue.nextTick(() => {// DOM更新完成 })
-
組件級更新:
-
每個組件對應一個渲染 Watcher
-
通過?
shouldUpdate
?鉤子優化
-
-
靜態樹提升:
-
編譯時標記靜態子樹
-
跳過不必要的 diff 比對
-
7. 與其他設計模式的對比
特性 | Vue | React | Angular |
---|---|---|---|
初始化方式 | 選項式/組合式API | 函數式組件 | 裝飾器類 |
響應式原理 | getter/setter | 手動setState | Zone.js臟檢查 |
變更檢測 | 自動依賴追蹤 | 手動/自動混合 | 臟檢查循環 |
機制 | Vue 2.x | React 16+ | Angular |
---|---|---|---|
變更檢測 | 細粒度依賴追蹤 | 虛擬DOM diff | 臟檢查循環 |
更新粒度 | 組件級 | 纖維節點級 | 組件級 |
數據綁定 | 雙向綁定 | 單向數據流 | 雙向綁定 |
異步更新 | nextTick 隊列 | 優先級調度 | Zone.js 控制 |
模板處理 | 編譯時優化 | JSX 運行時處理 | 編譯時優化 |
理解?new Vue()
?的完整初始化過程,有助于:
-
更高效地使用Vue框架
-
更好地調試應用問題
-
編寫更合理的組件代碼
-
實現高級定制功能