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 ~~~
';