This is the second day of my participation in the August More Text Challenge

preface

Mixins are the last thing I mentioned when I looked at parameter merging. Vue. Extend () uses the same merge strategy that applies to mixins. Today we’ll look at a concrete implementation of extend:

Vue.extend

Vue.extend is a global API defined in SRC /core/global-api/extend.js

export function initExtend (Vue: GlobalAPI) {
  /** * Each instance constructor, including Vue, has a unique * cid. This enables us to create wrapped "child * constructors" for prototypal inheritance and cache them. * /
  Vue.cid = 0
  let cid = 1

  /** * Class inheritance */
  Vue.extend = function (extendOptions: Object) :Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if(process.env.NODE_ENV ! = ='production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}
Copy the code

Vue.extend constructs a ‘subclass’ of Vue that takes an object containing component options as an argument. So let’s see what this code actually does. Okay

SuperId

const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
  return cachedCtors[SuperId]
}
Copy the code

As you can see from the code, the SuperId primarily works with cachedCtors to serve the cache. Here this is the caller of the extend method, which is Vue.

Take a look at cid:

/** * Each instance constructor, including Vue, has a unique * cid. This enables us to create wrapped "child * constructors" for prototypal inheritance and cache them. * /
Vue.cid = 0
let cid = 1
Copy the code

You can see from the comments above that each instance, including Vue, has a unique CID to identify itself. So the SuperId is unique.

It also checks if the passed extendOptions object has a _Ctor attribute, and if it does not, it assigns an empty object to _Ctor.

validateComponentName

Next we process the component name, which is used if the extension object passed in the name field, otherwise we get it from the Options object of the Super class.

const name = extendOptions.name || Super.options.name
Copy the code

To determine if the component name is valid, we call the validateComponetName method, defined in SRC /core/util/options.js

export function validateComponentName (name: string) {
  if (!new RegExp(`^[a-zA-Z][\-\.0-9_${unicodeRegExp.source}] * $`).test(name)) {
    warn(
      'Invalid component name: "' + name + '". Component names ' +
      'should conform to valid custom element name in html5 specification.')}if (isBuiltInTag(name) || config.isReservedTag(name)) {
    warn(
      'Do not use built-in or reserved HTML elements as component ' +
      'id: ' + name
    )
  }
}

Copy the code

SRC /core/util/lang.js: SRC /core/util/lang.js: SRC /core/util/lang.

Sub

Here’s the focus of the extend function, which converts an object into a constructor that extends from Vue via stereotype inheritance. As you can see, every time Sub is instantiated, _init goes through Vue initialization logic.

const Sub = function VueComponent (options) {
  this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub

Sub['super'] = Super
Copy the code

The Sub constructor uniquely flags CID by 1, and then calls mergeOptions to merge the parameters.

Sub.cid = cid++
Sub.options = mergeOptions(
  Super.options,
  extendOptions
)
Copy the code

After merging the parameters, initialize props and computed

if (Sub.options.props) {
  initProps(Sub)
}
if (Sub.options.computed) {
  initComputed(Sub)
}
Copy the code

Copy the extend, mixin, use, and hook methods of the parent class to the subclass

// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use


ASSET_TYPES.forEach(function (type) {
  Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
  Sub.options.components[name] = Sub
}
Copy the code

Save the options parameters of the parent class and the component object itself, as well as the extendOptions object originally passed in

// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
Copy the code

Caches the Sub object into the _Ctor object with the cid key of the parent class

// cache constructor
cachedCtors[SuperId] = Sub
return Sub
Copy the code