当你调用 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框架
-
更好地调试应用问题
-
编写更合理的组件代码
-
实现高级定制功能