Vue.js 在初始化阶段,会执行一些配置的合并。将所有配置合并到$options上。主要分为外部调用场景下的配置合并(也就是执行new Vue()时)和组件场景的配置合并(也就是子组件初始化时)。
// merge options
if (options && options._isComponent) {
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor), // Vue.options
options || {}, // vm.options
vm
)
}
在外部调用场景中(new Vue()时),由于options._isComponent不存在,因此执行 else 的逻辑。非常明确,使用mergeOptions函数将配置合并到$options上。接下来看一下是如何合并的。
export function resolveConstructorOptions (Ctor: Class<Component>) {
let options = Ctor.options
if (Ctor.super) {
// 此时Vue.super为undefined,所以不进入if判断
}
// 该函数返回Vue.options
return options
}
第一个参数resolveConstructorOptions(vm.constructor),Vue.super不存在,因此直接返回Vue.options作为第一个参数。
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
// Apply extends and mixins on the child options,
// but only if it is a raw options object that isn't
// the result of another mergeOptions call.
// Only merged options has the _base property.
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 = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
// strats是config的属性(是一个对象),对象中定义了不同的方法。对于不同的key值(比如data、watch等等)执行不同的合并策略,此处是获取相应的方法
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
在mergeOptions中,首先对用户传递的配置对象的 mixins 和 extends 递归调用mergeOptions。 紧接着对 Vue.options 和 options 执行mergeField,在mergeField中针对不同的属性执行不同的合并策略。最终将合并好的配置返回赋值给$options。接下来看组件中的配置合并。
export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
const opts = vm.$options = Object.create(vm.constructor.options)
opts.parent = options.parent
opts._parentVnode = options._parentVnode
// ...
if (options.render) {
opts.render = options.render
opts.staticRenderFns = options.staticRenderFns
}
}
组件的配置执行了initInternalComponent(vm, options)函数。以Vue.options为原型( Vue 为子组件的构造器)创建对象,赋值给$options。再扩展一些其他的属性。以下Vue.extend是对子组件构造器处理时的mergeOptions。
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.options = mergeOptions(
Super.options,
extendOptions
)
// ...
return Sub
}