The life cycle of the instance begins with the execution of the initialization function, where you can see the functionality that each module integrates with the instance, which will be explored in a separate article. Now look at the detailed code for the class initialization function.
Refer to the head
* the following code in the vue/SRC/core/instance/init. Js
import config from '.. /config'
import { initProxy } from './proxy'
import { initState } from './state'
import { initRender } from './render'
import { initEvents } from './events'
import { mark, measure } from '.. /util/perf'
import { initLifecycle, callHook } from './lifecycle'
import { initProvide, initInjections } from './inject'
import { extend, mergeOptions, formatComponentName } from '.. /util/index'
Copy the code
Some of the methods for header injection are functions that are initialized at the start of a lifecycle run, which were mentioned earlier in the Core class implementation article and will not be expanded here. As a basic configuration parameter, the config object will change its attribute value to adapt to different platform requirements in different operating environments. In this file, only the performance detection attribute is used, which is not closely related to the implementation of specific classes. The mark, Measure and formatComponentName methods are used to evaluate performance.
The utility methods extend and mergeOptions are used to initialize components.
Auxiliary function extend
The extend function is a very simple method to extend the properties of the object, the code is located in the file vue/ SRC /shared/util.js, the specific implementation is very basic, look good.
/** * Mix properties into target object. */
export function extend (to: Object, _from: ? Object) :Object {
for (const key in _from) {
to[key] = _from[key]
}
return to
}
Copy the code
The auxiliary function mergeOptions
MergeOptions function code is located in the vue/SRC/core/util/options, js, it is initialized to merge options object when the very important function, in order to see it in the initialization function USES, spend a little time to have a look at it carefully.
// This function is used to merge two configuration objects into one new configuration object,
// Core entities are used for both instantiation and inheritance
/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. */
// Export mergeOptions
// Receive parent and child parameters of Object type and VM parameters of Component type
// The function returns an object
export function mergeOptions (parent: Object, child: Object, vm? : Component) :Object {
// Check for improper reference component names in the Components property of the Child object when not in production
// Improper component names refer to component names such as slot,component that are the same as Vue built-in HTML tags or reserved tag names
// See L246 through L269 in the same file for details
// The auxiliary utility functions are located in SRC /shared/util.js L94 through L112
if(process.env.NODE_ENV ! = ='production') {
checkComponents(child)
}
// If child is passed as a function object, the options attribute of the function is assigned to the child, ensuring that the child references options
if (typeof child === 'function') {
child = child.options
}
// The following three functions format the attributes of the child into a predefined object format
// Normalize attributes
normalizeProps(child, vm)
// Normalize injection
normalizeInject(child, vm)
// Standardize instructions
normalizeDirectives(child)
// Define the extension
const extendsFrom = child.extends
// If there is a recursive merge down
if (extendsFrom) {
parent = mergeOptions(parent, extendsFrom, vm)
}
// If there are mixins, merge each mixin object
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
// Define an empty object, options
const options = {}
let key
// Merge the attributes in each parent and add them to options
for (key in parent) {
mergeField(key)
}
// If the parent does not contain the key attribute, merge the key attribute in each child
for (key in child) {
if(! hasOwn(parent, key)) { mergeField(key) } }// Define the mergeField function that takes the key argument
function mergeField (key) {
// If strats[key] has a defined merge strategy function, it is copied to strat
// Otherwise, the default defaultStrat method is assigned to strat
const strat = strats[key] || defaultStrat
// Merge attributes
options[key] = strat(parent[key], child[key], vm, key)
}
// Returns the final options object
return options
}
Copy the code
Although the implementation of mergeOptions is a bit complicated, its function is actually quite clear. It is to resolve the conflict between the inherited class options object and the newly passed options object in the initialization process, that is, to use the inherited property value or the newly passed property value problem. It is officially stated at the beginning of the code that this is a recursive function that can be used to handle both extension and mixins scenarios. In short, this step is to ensure that the options object of our initialized instance is correctly unique.
There are several standardized attribute functions in the code, and the specific implementation is also in the same file as the above code. Although there are a lot of codes, the implementation is relatively simple, the main purpose is to format each attribute of the options object into a predetermined format based on the object, which is convenient to use in the future operation.
HasOwn function is the Object. The prototype. HasOwnProperty method is a wrapper, simpler, need to know if you go to util tool function file viewer.
It is worth mentioning the use of Strats. Define the Strats variable at the beginning of the code and explain that it is used to handle parent-child option merging properties.
/** * Option overwriting strategies are functions that handle * how to merge a parent option value and a child option * value into the final value. */
const strats = config.optionMergeStrategies
Copy the code
The merging strategy for el and propsData attributes gives defaultStrat the principle that the child attribute takes precedence and that the parent attribute is returned in the absence of the child attribute.
/** * Options with restrictions */
if(process.env.NODE_ENV ! = ='production') {
strats.el = strats.propsData = function (parent, child, vm, key) {
if(! vm) { warn(`option "${key}" can only be used during instance ` +
'creation with the `new` keyword.')}return defaultStrat(parent, child)
}
}
Copy the code
Data, watch, props, methods, Inject, computed, provide, various hook functions and component, directive, and filter contained in ASSET_TYPES all define related merge methods respectively. For those of you who are interested in learning more, you can check it out in the same file. The code is too long but the implementation is fairly basic, so there is nothing more to say. The only thing you can focus on is that some properties are substitution overlays and some properties are merged into arrays such as listener functions for various hooks.
Merges options when initializing internal components
InitInternalComponent (VM, options) initInternalComponent(VM, options) initInternalComponent(VM, options)
// Outputs initInternalComponent
// Accept Component VM parameters and InternalComponentOptions parameters
// Where vm and options are instance objects and configuration objects to be passed in when the instance is created
export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
// Define opts and create objects modeled after vm.constructive. options for opts and vm.$options
const opts = vm.$options = Object.create(vm.constructor.options)
// The following is manual assignment, which is intended to improve performance because it is faster than dynamically enumerating attributes
// doing this because it's faster than dynamic enumeration.
// Define and assign the parent virtual node parentVnode
const parentVnode = options._parentVnode
// Set the opts object properties parent and _parentVnode
opts.parent = options.parent
opts._parentVnode = parentVnode
// Define and assign vnodeComponentOptions
const vnodeComponentOptions = parentVnode.componentOptions
// Define opTS attributes
opts.propsData = vnodeComponentOptions.propsData
opts._parentListeners = vnodeComponentOptions.listeners
opts._renderChildren = vnodeComponentOptions.children
opts._componentTag = vnodeComponentOptions.tag
// Opts render and staticRenderFns are set if the opts render and staticRenderFns properties are present
if (options.render) {
opts.render = options.render
opts.staticRenderFns = options.staticRenderFns
}
}
Copy the code
The initInternalComponent function is simple. It manually assigns values to the options object of the created internal component to improve performance, because initialization of all internal components is not handled outside the column. While the scenario of when internal components will be created is not well understood, it is clear that the common use of creating Vue instances to initialize view pages is non-internal. Leave a question here.
Merges options when initializing instances
The following three functions are used to initialize the instance to merge the options line, and the last two functions are used to assist. The corresponding code is as follows. It is used to solve the merging problem between default configuration options and extension options of constructors.
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
Copy the code
/ / export resolveConstructorOptions function, accept Ctor Component constructor parameters
export function resolveConstructorOptions (Ctor: Class<Component>) {
// Define the options property of the constructor passed in
let options = Ctor.options
// If ctor. super exists, execute the following code, which is used to determine whether the instance object has inheritance
// Recursively merge the options of the inherited parent object if any
if (Ctor.super) {
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
if(superOptions ! == cachedSuperOptions) {// If the parent's option changes, update it
// super option changed,
// need to resolve new options.
Ctor.superOptions = superOptions
// Check if there are any late changes/add-ons to resolve the problem of accidentally deleting injection options
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions(Ctor)
// Extend ctor.extendOptions if options are returned with modifications
// update base extend options
if (modifiedOptions) {
extend(Ctor.extendOptions, modifiedOptions)
}
// Merge inheritance options and extension options
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
// Set a reference to options.components[options.name]
if (options.name) {
options.components[options.name] = Ctor
}
}
}
/ / return options
return options
}
// The following two functions are solutions to the #4976 problem
// Define resolveModifiedOptions, which takes Ctor arguments and returns Object
function resolveModifiedOptions (Ctor: Class<Component>): ?Object {
// Define the Modified variable to store attributes that will eventually be selected to remain
let modified
// Define the latest, extended, and sealed configuration options respectively
const latest = Ctor.options
const extended = Ctor.extendOptions
const sealed = Ctor.sealedOptions
// Iterate over the incoming configuration option object
for (const key in latest) {
// If the latest attribute is not equal to the sealed attribute, de-processing is performed
if(latest[key] ! == sealed[key]) {if(! modified) modified = {} modified[key] = dedupe(latest[key], extended[key], sealed[key]) } }/ / returns the modified
return modified
}
// Define the dedupe function to accept latest, extended, sealed
function dedupe (latest, extended, sealed) {
// Compare the latest and sealed attributes when merging options to ensure that the lifecycle hooks do not duplicate
// compare latest and sealed to ensure lifecycle hooks won't be duplicated
// between merges
// If latest is array
if (Array.isArray(latest)) {
// Define the res variable
const res = []
// Format sealed and extended as array objects
sealed = Array.isArray(sealed) ? sealed : [sealed]
extended = Array.isArray(extended) ? extended : [extended]
for (let i = 0; i < latest.length; i++) {
// Returns the attributes of the latest object existing in the extended options instead of sealing options to exclude duplicates
// push original options and not sealed options to exclude duplicated options
if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) {
res.push(latest[i])
}
}
// Return an array variable containing the extension options
return res
} else {
// If not, return latest
return latest
}
}
Copy the code
ResolveConstructorOptions function solves the inheritance after the constructor of the option, the newly created instance of vm $options object is inheriting option and create the incoming options options. There are a lot of complex recursive calls, but it’s important to understand that the purpose of these functions is to determine the final option.
The execution of the initialization function is not only to start the operation of the life cycle, but also provides a very complex but sound solution to the problem of how to choose and choose each attribute value of the Options object, which lays a solid foundation for the normal operation of the life cycle. With clear options, the subsequent functions can be smoothly executed as scheduled. You can also see here the merging principles that Vue handles for various attributes, and a good understanding of this ensures that problems encountered are immediately located when used.