【源码剖析】new Vue 发生了什么
说明
- vue 业务代码写了几年,对其痛点有了相应了解,想更深入理解其痛点原因。
 - 学习源码中的思路,了解其 api 输出的原理。
 - vue2.6 已经到终版,对比大佬之前版本的源码分析,可以看其最后某些代码优化。
 
代码剖析
new 关键字在 Javascript 语言中代表实例化是一个对象,而 Vue 实际上是一个类,类在 Javascript 中是用 Function 来实现的。所以我们得找到Vue函数,从而去分析其函数执行究竟做了些什么
/src/core/instance/index.js
1  | function Vue(options) {  | 
可以看到 Vue 只能通过 new 关键字初始化,然后会调用 this._init 方法
src/core/instance/init.js
1  | export function initMixin(Vue: Class<Component>) {  | 
上述代码只是在 Vue 的原型上增加_init方法,构造 Vue 实例的时候会调用这个_init方法来初始化 Vue 实例。
接下来我们逐段分析Vue.prototype._init方法中的代码:
1  | if (options && options._isComponent) {  | 
这段主要是对 Vue 提供的 props、data、methods 等选项进行合并处理。会将我们传入的 options 合并到vm.$options上。我们可以通过 vm.$option.el,访问到我们options传入的 el。
跳过内部函数,接着往下执行可以看到:
1  | /* istanbul ignore else */  | 
这里主要是设置渲染函数的作用域代理,其目的是提供更好的提示信息(如:在模板内访问实例不存在的属性,则会在非生产环境下提供准确的报错信息)
再往下执行可以发现,new Vue最重要的部分。
1  | /*初始化生命周期*/  | 
从上述代码,不难看出:Vue 初始化主要执行了:初始化生命周期initLifecycle、初始化事件中心initEvents、初始化渲染initEvents、初始化 data、props、methods、computed、watch; 调用 beforeCreate 钩子函数并且触发 beforeCreate 钩子事件;调用 created 钩子函数并且触发 created 钩子事件。
在初始化的最后的代码
1  | if (vm.$options.el) {  | 
判断是否有了属性,如果有 el 属性,则调用 vm.$mount 方法挂载 vm,挂载的目标就是把模板渲染成最终的 DOM。
总结
全文从构造函数Vue开始,执行 new Vue() 调用 Vue 的原型方法Vue.prototype._init() 方法,依次处理:
- 合并配置
 - 设置渲染函数的作用域代理
 - 初始化生命周期
initLifecycle(vm) - 初始化事件
initEvents(vm) - 初始化渲染(render)
initRender(vm) - 调用 beforeCreate 钩子函数并且触发 beforeCreate 钩子事件
callHook(vm, 'beforeCreate') - 初始化 data、props、methods、computed、watch 等
initState(vm); - 调用 created 钩子函数并且触发 created 钩子事件
callHook(vm, 'created') - 挂载 el
vm.$mount(vm.$options.el) 
下一章节,先去分析其中比较简单的一部分initState(vm),这部分主要是 props,methods,data,computed,watch 初始化。
下一章: 【源码剖析】initState 初始化
本章: 【源码剖析】new Vue 发生了什么