Initializing the constructor vue is essentially a constructor. When we new vue, we must pass its constructor, so we first find its directory \vue-dev\ SRC \core\instance\index.js.

\vue-dev\src\core\instance\index.js

/ *

  • @author: A warbler
  • @description: Vue is actually a class implemented with Function. We can only instantiate it with new Vue.
  • @Date: 2021-07-07 17:46:27
  • @LastEditTime: 2021-07-09 19:08:26
  • @FilePath: \vue-dev\src\core\instance\index.js

* /

Function Vue (options) {if (process.env.node_env!) {if (process.env.node_env! The == ‘production’ && // instanceof operator is used to check whether the constructor’s prototype property appears on the prototype chain of an instance object. // Vue must be a new instantiation of the es5 implementation of class (via function)! (this instanceof Vue) warn(‘Vue is a constructor and should be called with the new keyword’)} This method is defined in initMixin, and its input parameter options is the object we passed when we defined the object this._init(options)}

/ * *

  • The xxxMixin method is executed to initialize the related function definition. This is just to define the function, which will be used for reanalysis later
  • Each Mixin adds some properties or methods to a Vue prototype

* /

// Merge configure initMixin(Vue) // Initialize Data, props, computed, and Watcher stateMixin(Vue) // Initialize the event center eventsMixin(Vue) // Initialize the lifecycle by calling the declaration cycle hook function LifecycleMixin (Vue) // initialize renderMixin(Vue)

⭐ Vue is actually a class implemented with Function, so we can only instantiate it with new Vue and then call this._init. ⭐ why is Vue not implemented using ES6 classes? As you can see below the constructor, many xxxMixin function calls are made, passing in Vue as arguments. Their function is to extend some methods on Vue’s prototype. Vue implements these extensions in multiple modules by function, rather than implementing all of them in one module. This approach is difficult to implement with Class. The advantage of doing this is that it is very easy to maintain and manage the code, and the programming skills are well worth learning. Let’s conclude with a mind map

Next let’s look at what happens to this._init(options). The _init method is added to the prototype of Vue in initMixin.

\vue-dev\src\core\instance\init.js

initMixin / _init /**

  • @description: Define vue.prototype. _init
  • @param {*} Vue Vue constructor

*/ export function initMixin (Vue: Class) {

/ * *

  • Mount a _init method on the Vue prototype
  • Responsible for Vue initialization process

*/ Vue.prototype._init = function (options? : Object) {

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` part I ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` / / get the vue instance const vm: Component = this // Each vue instance has a _uid and increments to ensure uniqueness vm._uid = ID ++ // Vue instances should not be responsive, mark vm._isVue = true

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` second part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

$options, vue will put all related properties and methods into the vm.$options to prepare for subsequent calls. The Vue $option attribute comes from two aspects, one of which is predefined by Vue's vm.constructor. One is the input object passed in when new Vue */ if (options && options._isComponent) {/** * If a child component is initialized here, only some performance optimizations have been made * to put some deep properties on the component configuration object $options to improve code execution efficiency */ initInternalComponent(VM, options)} else {/** * merge configuration items * if root component initialization goes here,, Merge the global configuration of Vue into the local configuration of the root component. For example, Vue.com Ponent registered global components are merged into the components option of the root instance. For each sub-component, the merge occurs in two places: * 2, {components: {xx}} way registered local components in the implementation of the compiler to generate options with the render function on a merger, including the components of the root component configuration (compiler) * / vm. $options = mergeOptions (before / / here is to get the default configuration, Component order filters, etc That is the constructor of the options resolveConstructorOptions (vm) constructor), the options | | {}, vm)}Copy the code

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` third part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

// Execute initProxy function in non-production environment with instance; If (process.env.node_env! == 'production') {initProxy(vm)} else {vm._renderProxy = VM} set the _self attribute of the instance to its own vm. $parent, $children, $root, $refs, etc. InitLifecycle (VM) /** * initializes custom events, so we register events on < comp@click ="handleClick" />, listener is not the parent component, * is the child component itself, That is, event dispatchers and listeners are the child components themselves, // initEvents(vm) // render initializes the init slot, get this.slots, Call the beforeCreate life cycle function callHook(vm, beforeCreate life cycle function callHook(vm, beforeCreate). The init inject option gets the {key:val} configuration object and responds to the parse result. And proxy each key to the VM instance initInjections(VM) // resolve injections before data/props // Data initialization is the core of the responsive principle, handling props methods computed Data Watch // initState(VM) // parse the provide object on the component configuration item, InitProvide (VM) // resolve provide after data/props // Call the created hook function to perform the created lifecycle callHook(VM, 'created') // The beforeCreate life cycle cannot access the data because it has not been initialized yet but can get relational properties, slots, custom eventsCopy the code

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` fourth part ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `

/** * if vm.$options has el attribute, call vm.$mount method to mount vm. */ if (vm.$options.el) {// call the $mount method, Vm.$mount(vm.$options.el)}Copy the code

}} Copy the code initInternalComponent /**

  • $options to flatten the properties on the configuration object to reduce run-time prototype chain lookup and improve execution efficiency
  • @param {*} VM component instance
  • @param {*} options The configuration passed in

* /

export function initInternalComponent (vm: Component, options: InternalComponentOptions) {

// Create vm. optionSConStopts =vm.options based on the configuration object on the component constructor constopts=vm. optionsConstopts =vm.options = Object.create(vm.constructor.options)

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` configuring component incoming some assigned to the vm. The $options on ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` Sunday afternoon const parentVnode = options. _parentVnode opts. Parent = options.parent opts._parentVnode = parentVnode

const vnodeComponentOptions = parentVnode.componentOptions opts.propsData = vnodeComponentOptions.propsData opts._parentListeners = vnodeComponentOptions.listeners opts._renderChildren = vnodeComponentOptions.children opts._componentTag = vnodeComponentOptions.tag

/ / ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` configuring component incoming some assigned to the vm. The $options on ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ∨

// If there is a render function, $options if (opts.render) {opts.render = opts.render opts.staticrenderfns = opts.staticrenderfns}} Copy code resolveConstructorOptions / * *

  • @description: Resolves the options property on instance constructor and merges base class options
  • @param {*} Ctor instance constructor
  • @return {*} options Configures options

* /

export function resolveConstructorOptions (Ctor: Class) {// Get the configuration from the instance constructor options let options = ctor. options if (ctor.super) {** * ctor. super is subclassed by Vue. The vue. extend method adds a super attribute to Ctor, If there is super on the constructor, Ctor is a subclass of Vue. Extend. In other words, Ctor checks for the parent component and then retrieves the configuration options on the base class recursively, that is, the set of all superior options */ const superOptions = resolveConstructorOptions(Ctor.super)

// Ctor. SuperOptions: Options on the parent component's Vue constructor, such as directives,filters,.... const cachedSuperOptions = Ctor.superOptions if (superOptions ! == cachedSuperOptions) {// If the parent component was changed, Update superOption ctor. superOptions = superOptions // Check for any late modifications/additional options on ctor. options const modifiedOptions = ResolveModifiedOptions (Ctor) if (modifiedOptions) {resolveModifiedOptions Extend (Ctor. ExtendOptions, modifiedOptions)} // Options options = Ctor. Options = mergeOptions(superOptions, Ctor.extendOptions) if (options.name) { options.components[options.name] = Ctor } }Copy the code

} // If ctor. super does not exist, such as using the new keyword to create a new instance of the Vue constructor directly returns options of the underlying constructor.

Copy the code resolveModifiedOptions /**

  • @description: Check if there are any late changes/additional options
  • @param {*} Ctor instance constructor
  • @return {*} modified

* /

function resolveModifiedOptions (Ctor: Class): ? Const latest = ctor. options // Sealed constructor options, Backup const sealed = Ctor. SealedOptions for (const key in latest) {if (latest[key]! == sealed[key]) { if (! Modified = {} Modified [key] = latest[key]}}

Through the code, we break down the _init process into four parts. Here is a brief overview of what has been done, the specific code will be analyzed in detail later. Part 1 ⭐ Each Vue instance has a _UID, which is incremented to ensure uniqueness. ⭐ vue instance should not be reactive, mark it. The second part ⭐ if it is a child component, put some of the deeper properties on the component configuration object in the vm. options option to improve the execution efficiency of the code. ⭐ If the root component is merged with options, vue will put related properties and methods into the VM. options option to improve the efficiency of code execution. ⭐ If the root component is merged with options, vue will put related properties and methods into the VM. options option to improve the efficiency of code execution. ⭐ If it is the root component and options are merged, vue will put all related properties and methods into vm.options. The vm. options properties come from two aspects, one predefined by Vue’s constructor, vm.constructor, and the input object passed in to newVue. The third part ⭐initProxy/vm.renderProxy executes the initProxy function in a non-production environment, with an instance as the parameter; The renderProxy property of the instance is set to the instance itself in production. ⭐ sets the instance’s self attribute to the instance itself. ⭐initLifecycle initializes component instance relationship properties, such as options properties, from two aspects, one predefined by Vue’s constructor, vm.constructor, and one incoming parameter object passed in when new Vue. The third part ⭐ initProxy/vm._renderProxy executes the initProxy function in a non-production environment with the instance as the parameter; The _renderProxy attribute of the instance is set to the instance itself in production. ⭐ sets the _self attribute of the instance to the instance itself. ⭐ initLifecycle initializes component instance relationship properties, such as options properties, from two aspects, one predefined by Vue’s constructor, vm.constructor, and one incoming parameter object passed in when newVue. The third part ⭐initProxy/vm.renderProxy executes the initProxy function in a non-production environment, with an instance as the parameter; The renderProxy property of the instance is set to the instance itself in production. ⭐ sets the instance’s self attribute to the instance itself. ⭐initLifecycle initializes component instance relationship properties, such as parent, children, children, root, refs, etc. ⭐initEvents Initializes custom events. ⭐initRender initializes slots, gets this.slots, and defines this.c, the createElement method, as the usual h function. ⭐callHook executes the beforeCreate life cycle function. ⭐initInjections initialize inject option ⭐initState is the core of the responsive principle, dealing with props, methods, computed, data, watch, etc. ⭐initProvide parses the provide object on the component configuration item and mounts it to the VM. Provided property. ⭐callHook performs created lifecycle functions. ⭐ if there is an EL attribute, call vm.refs, etc. ⭐ initEvents Initializes custom events. ⭐ initRender initializes slots, gets this.slots, and defines this._c, the createElement method, as the h function normally used. ⭐ callHook executes the beforeCreate life cycle function. ⭐ initInjections initialize inject option ⭐ initState is the core of the responsive principle, dealing with props, methods, computed, data, watch, etc. ⭐ initProvide parses the provide object on the component configuration item and mounts it to the vm._provided property. ⭐ callHook performs created lifecycle functions. ⭐ if there is an EL attribute, call vm.refs, etc. ⭐initEvents Initializes custom events. ⭐initRender initializes slots, gets this.slots, and defines this.c, the createElement method, as the usual h function. ⭐callHook executes the beforeCreate life cycle function. ⭐initInjections initialize inject option ⭐initState is the core of the responsive principle, dealing with props, methods, computed, data, watch, etc. ⭐initProvide parses the provide object on the component configuration item and mounts it to the VM. Provided property. ⭐callHook performs created lifecycle functions. The fourth part ⭐, if it has an EL attribute, calls the vm.mount method to mount the VM, with the goal of rendering the template into the final DOM. ⭐ If the EL does not exist, you need to manually mount it. Let’s conclude with a mind map

Js reference Vue technology disclosure master Vue stack source code principle this article by Li Yongning tutorial combined with their own ideas to sort out, in this special thanks to the predecessors.

Author: A Warbler Link: juejin.cn/post/698458… The copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.