Vue — new实例做了什么
最后更新于:2022-04-02 08:12:37
>[success] # Vue 实例做了什么
~~~
1.读整个源码之前,在上一个章节我们已经明确了入口,另外一种明确入口思路是根据生命周期图,
可以发现整个'vue' 运行开始都在这个'new Vue'创建实例时候,因此我们需要找到'Vue'这个构造函数
2.也可以通过简暴力的方法在'vue\dist\vue.esm.js' 的文件夹中,直接搜Vue 的构造函数
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/1a/fa/1afa482800e27735081b973675635ac6_731x366.png)
>[info] ## vue.esm.js 里的Vue构造函数
~~~
1.当找到'vue'构造函数代码如下,其实发现在Vue 构造函数中执行了一个'_init' 的方法,这个方法经过
定位后其实不难发现,他是通过'initMixin'方法 在vue 原型链上加入的
2.在上一个章节分析的时候,实际已经找到了'vue.esm.js'生成前打包对应的入口,
也找到了'Vue构造函数在打包前声明的文件位置':'src\core\instance\index.js'
,在这个文件里也发现了一个'initMixin'方法,该方法在'src\core\instance\init.js'
~~~
* vue.esm.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);
}
initMixin(Vue);
~~~
>[danger] ##### 分析 initMixin 方法做了什么
~~~
1.找到在'src\core\instance\init.js' 'initMixin'的方法
2.'initMixin'就做了一件事情,在Vue的原型上增加_init方法,构造Vue实例的时候会调用这个
'_init'方法来初始化'Vue'实例
2.可以在代码中看到,在初始化的时候一并做了这些操作
initLifecycle(vm) // 初始化生命周期
initEvents(vm) // 初始化事件
initRender(vm) // 初始化渲染
callHook(vm, 'beforeCreate') // 调用生命周期钩子函数
initInjections(vm) //初始化injections
initState(vm) // 初始化props,methods,data,computed,watch
initProvide(vm) // 初始化 provide
callHook(vm, 'created') // 调用生命周期钩子函数
~~~
~~~js
initMixin (Vue: Class) {
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
if (options && options._isComponent) {
// 优化内部组件实例化
// 因为动态选项合并非常慢,而且
// 内部组件选项需要特殊处理。
initInternalComponent(vm, options)
} else {
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) // 初始化渲染
callHook(vm, 'beforeCreate') // 调用生命周期钩子函数
initInjections(vm) //初始化injections
initState(vm) // 初始化props,methods,data,computed,watch
initProvide(vm) // 初始化 provide
callHook(vm, '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)
}
}
}
~~~
>[danger] ##### 简单总结
~~~js
1.vue 在构造函数内部调用 `_init`方法
2.`_init` 方法是在`initMixin`方法里面定义的
3.`initMixin`方法里面做了如下事情:
3.1`initLifecycle(vm)`// 初始化生命周期
3.2.`initEvents(vm)`// 初始化事件
3.3.`initRender(vm)`// 初始化渲染
3.4.`callHook(vm, 'beforeCreate')` // 调用生命周期钩子函数
3.5.`initInjections(vm)` //初始化injections
3.6.`initState(vm)` // 初始化props,methods,data,computed,watch
3.7.`initProvide(vm)` // 初始化 provide
3.8.`callHook(vm, 'created')` // 调用生命周期钩子函数
4.最后调用了`$mount`挂载的目标就是把模板渲染成最终的 DOM
~~~
';