This is the sixth day of my participation in the First Challenge 2022.

Previously on & Background

In the preceding text, the light xi Vue sources-4-new Vue()

  1. We analyzed the origin of the Vue constructor, it is in the SRC/core/instance/index in js statement;

  2. There is only one core line in the Vue constructor: this._init()

  3. This._init () is a method that extends to vue.prototype on the initMixin() method;

  4. _init() details the logic:

    • 4.1 vmVueAn instance of “, appears latervmTo think ofVueAn instance of the;
    • 4.2 according to theoptions._isComponentProcess the merge of options, and the root instance is obtainedvm.$optionsProperties;
    • 4.3 the agent_renderProxyvm;
    • 4.4 A series of initialization andbeforeCreatedcreatedHook calls;
    • 4.5 Final Basisvm.$options.elProperty determines whether to callvm.$mountMethods Implement mount;

This section will continue to focus on the mergeOptions details of the _init method, the core of new Vue. $options. Get the details of vm.

Merge options in _init

When components are merged, a different merge method is selected based on options._isComponent. If it is a component, the initInternalComponent method is executed; otherwise, mergeOptions is executed and the return value is the value of vm.$options:

if (options && options._isComponent) {
  initInternalComponent(vm, options)
} else {
  vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor), // Vue...
    options || {},
    vm
  )
}
Copy the code

It is clear from the diagram that when implemented tonew VueThe time,vm._isComponentundefined, so will goelse, the implementation ofmergeOptionsMethods:

2.1 resolveContructorOptions method

Position statement is: the SRC/core/instance/init. Js – > resolveConstructorOptions

Before you say mergeOptions said resolveConstructorOptions method, because mergeOptions method receives the resolveConstructorOptions methods return values.

This method resolves the options property of the constructor from the component’s constructor, and does different things depending on whether Ctor has a super parent. If Ctor does not exist, it returns options. Ctor is Vue itself, shows the current is creating the root instance, when our new executive resolveConstructorOptions Vue is this logic;

Note that the constructor refers to the Vue itself when the current new Vue is created, but when a component is created later, such as someCom in our test.html subcomponent, the subcomponent’s constructor is actually a subclass of Vue;

export function resolveConstructorOptions (Ctor: Class<Component>) {
  Cache: {model, show}, Component: {keepAlive, Transition,} filter: {}
  // I wonder when these things were added.
  // added when intGlobalApi is called in core/index.js via extend(vue. options, 'XXXX ', builtInxxx)
  let options = Ctor.options
  
  // So all the statements in the if condition create the component, so the root instance is created, ignoring the logic for now
  if (Ctor.super) {
  }
  return options
}
Copy the code

Let’s take a look at what vue. options contains:

The object is the time to create initGlobalAPI has been said before, in which the components/directives/filter corresponding to the: Global components, global directives, global filters, the KeepAlive in global components is the
that we use, the V-Model in directives is the V-model, and the _base is the Vue constructor itself.

In conclusion, before calling mergeOptions call resolveConstructorOptions is Vue. When otpions this object.

2.2 mergeOptions

Method declaration location: SRC /core/util/options.js

Methods:

  1. Receiver parent optionparentThe child optionschild, andvmInstance, merges parent and child options, and is normalizedProps, inject, directivesTo facilitate further processing of these options later;
  2. whenchildThere is no_baseAttribute indicates that noVue.optionsAnd at the same timechildmixinextendsProperty, willextendsmixinMerge to parent optionparent;
  3. When merging options, if the same attribute is encountered, the child option overrides the parent option’s policy merge. Of course, you can also specify the policy. Finally, the merged options are returned
export function mergeOptions (
  parent: Object,
  child: Object, vm? : Component) :Object {
  if (typeof child === 'function') {
    child = child.options
  }

  // Standardize options for props, inject, directive for further processing
  NormalizeInject {from: key, default: XXX}. This data structure is used in the initInject method
  normalizeProps(child, vm)
  normalizeInject(child, vm)
  normalizeDirectives(child)

  // Handles extends and mixins on child objects, merging these inherited options into parent
  // The mergeOptions processed object has the _base attribute
  if(! child._base) {if (child.extends) {
      parent = mergeOptions(parent, child.extends, vm)
    }
    if (child.mixins) {
      for (let i = 0, l = child.mixins.length; i < l; i++) {
        parent = mergeOptions(parent, child.mixins[i], vm)
      }
    }
  }

  const options = {}
  
  // Iterate over the parent options, merge options, and process the same options, as shown in the mergeField method below
  let key
  // Iterate over the parent options
  for (key in parent) {
    mergeField(key)
  }

  // Go through the child options and merge the options that are not in the parent options into options,
  // Since the parent has the same property, it was already handled when the parent option was handled above, as in the previous for in loop
  for (key in child) {
    if(! hasOwn(parent, key)) { mergeField(key) } }// Merge fields, the child option overrides the child option
  function mergeField (key) {
    // Strats or defaultStrat is a merge strategy, that is, parent or child
    const strat = strats[key] || defaultStrat
    // The value of the child option is preferred
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}
Copy the code

To sum up, the new executive to mergeOptions Vue, first call resolveConstructorOptions get Vue. The options that have global components/instructions/filter options object, $options = mergeOptions; $options = mergeOptions; $options = mergeOptions; $options = mergeOptions;

2.3 combined Vue. The options of the original components/directives/filters to?

$options = someCom; $options = someCom; $options = someCom; Where did KeepAlive, Model/Show go?

In previous articles, it has been mentioned that mergeOpitons of Vue will be the implementation principle of Vue code reuse or global components or directives. Before we get to the answer, here’s a picture:

Use new options from vm.code.components.component.__proto__ () for KeepAlive. Use new options from vm.code.component.__proto__ ().

It is not difficult to see that VM finds these global components or instructions through the look-up mechanism of prototype chain, which is the implementation of global components we have been talking about. The implementation is not simply copied to every subinstance, but is implemented through inheritance. Here’s who did it:

In 2.2 mergeOptions, there is a method called mergeFiled at the bottom, which will provide the answer to the question:

2.4 mergeFile policy merge implements inheritance of global components

MergeFiled itself is not complicated. Parent properties are transferred to policies and merged with policies. The strats object is a constant, and the combination of various policies in the constant is made by the following code:

const strats = config.optionMergeStrategies;

// ASSET_TYPES = [
// 'component',
// 'directive',
// 'filter'
// ]
ASSET_TYPES.forEach(function (type) {
  strats[type + 's'] = mergeAssets
})
Copy the code

Can see from the above components components/directives/filters merger strategy all point to a mergeAssets method:

SRC /core/util/options.js -> mergeAssets

function mergeAssets (
  parentVal: ?Object,
  childVal: ?Object, vm? : Component, key: string) :Object {
  // object. create creates an Object based on parentVal
  const res = Object.create(parentVal || null)
  if(childVal) { process.env.NODE_ENV ! = ='production' && assertObjectType(key, childVal, vm)
    return extend(res, childVal)
  } else {
    return res
  }
}
Copy the code

Use new Vue.options.components (KeepAive) to create __proto__ from VM.options.com ponents. Because mergeFile(vue. options[‘components’], vm.$options[‘compoennts’]),

Next, call mergeAsset(vue. options[‘components’], vm.$options[‘compoennts’]) in mergeField and try to bring the two objects into mergeAssets.

Res = object.create (Vue. Options [‘components’]); Options [‘components’], there are KeepAlive global components, caching and filters the same way, will not be described here;

Third, summary

$options = mergeOptions(….) $options = mergeOptions(….) $options = mergeOptions(….) The logic;

  1. withresolveConstructorOptionsTo obtainVue.optionsOption object, this guy isinitGlobalAPICreate;
  2. mergeOptionsReceive parent option (Vue.options) and suboptions (new VuePass the options), perform the merge, during the standardization processinjectpropsAnd so on;
  3. MergeOptions mergerComponents, directives, filtersThere is a policy that causes the current instance to inherit globallyComponents, directives, filters