You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// src/core/instance/init.jsletuid=0
export functioninitMixin(Vue: Class<Component>){
Vue.prototype._init=function(options?: Object){constvm: Component=this// a uidvm._uid=uid++letstartTag,endTag/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){startTag=`vue-perf-start:${vm._uid}`endTag=`vue-perf-end:${vm._uid}`mark(startTag)}// a flag to avoid this being observedvm._isVue=true// merge optionsif(options&&options._isComponent){// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm,options)}else{vm.$options=mergeOptions(resolveConstructorOptions(vm.constructor),options||{},vm)}/* istanbul ignore else */if(process.env.NODE_ENV!=='production'){initProxy(vm)}else{vm._renderProxy=vm}// expose real selfvm._self=vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm,'beforeCreate')initInjections(vm)// resolve injections before data/propsinitState(vm)initProvide(vm)// resolve provide after data/propscallHook(vm,'created')/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){vm._name=formatComponentName(vm,false)mark(endTag)measure(`vue ${vm._name} init`,startTag,endTag)}if(vm.$options.el){vm.$mount(vm.$options.el)}}}
letstartTag,endTag/* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){startTag=`vue-perf-start:${vm._uid}`endTag=`vue-perf-end:${vm._uid}`mark(startTag)}// 中间代码.../* istanbul ignore if */if(process.env.NODE_ENV!=='production'&&config.performance&&mark){vm._name=formatComponentName(vm,false)mark(endTag)measure(`vue ${vm._name} init`,startTag,endTag)}
我们这边不做详细介绍,主要还是来看下中间部分的内容:
// a flag to avoid this being observedvm._isVue=true// merge optionsif(options&&options._isComponent){// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm,options)}else{vm.$options=mergeOptions(resolveConstructorOptions(vm.constructor),options||{},vm)}/* istanbul ignore else */if(process.env.NODE_ENV!=='production'){initProxy(vm)}else{vm._renderProxy=vm}// expose real selfvm._self=vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm,'beforeCreate')initInjections(vm)// resolve injections before data/propsinitState(vm)initProvide(vm)// resolve provide after data/propscallHook(vm,'created')
export functionresolveConstructorOptions(Ctor: Class<Component>){let options =Ctor.optionsif(Ctor.super){constsuperOptions=resolveConstructorOptions(Ctor.super)constcachedSuperOptions=Ctor.superOptionsif(superOptions!==cachedSuperOptions){// super option changed,// need to resolve new options.Ctor.superOptions=superOptions// check if there are any late-modified/attached options (#4976)constmodifiedOptions=resolveModifiedOptions(Ctor)// update base extend optionsif(modifiedOptions){extend(Ctor.extendOptions,modifiedOptions)}options=Ctor.options=mergeOptions(superOptions,Ctor.extendOptions)if(options.name){options.components[options.name]=Ctor}}}returnoptions}
通过上面调用时传递的参数 vm.constructor 知道,这里的 Ctor 是当前实例的构造函数,也就是 Vue 本身。那么这里一定是 Vue 吗?通过下面 if 判断中的 super 知道,Ctor 也有可能是个子类,因为只有之类才有 super 属性。也就是说 Ctor 有可能是通过 Vue.extend 创造的一个子类。
有了上面的理解,下面的 if 判断也比较好理解了。如果当前是 Vue 的实例,那么直接返回 Vue.options 的值。根据前面文章构造函数篇章知道,Vue.options 的值是通过全局 global-api 来初始化的,内容如下:
if(superOptions!==cachedSuperOptions){// super option changed,// need to resolve new options.Ctor.superOptions=superOptions// check if there are any late-modified/attached options (#4976)constmodifiedOptions=resolveModifiedOptions(Ctor)// update base extend optionsif(modifiedOptions){extend(Ctor.extendOptions,modifiedOptions)}options=Ctor.options=mergeOptions(superOptions,Ctor.extendOptions)if(options.name){options.components[options.name]=Ctor}}
通过上篇文章 Vue 源码学习(二)- 构造函数,我们知道了 Vue 的构造被多个函数包装处理,所以我们今天来分析下第一个包装函数
initMixin
,它到底做了哪些处理呢?初始化
我们可以看到,在
initMixin
方法中,在 Vue 的原型链上增加了_init
方法,这个方法是不是很眼熟,在分析构造函数的时候,它就调用了这个方法,原来是在这里定义的。首先声明了常量
vm
,指向当前Vue
实例,然后添加了一个唯一标示_uid
,其值为uid
。uid
初始值为0
,所以每次实例化一个Vue
实例之后,uid
的值都会自增++
。下面我们可以看到两段关于性能标记的代码,他们主要是对中间包裹的代码做性能追踪分析用的:
我们这边不做详细介绍,主要还是来看下中间部分的内容:
我们来逐行分析下,首先是在
Vue
实例上添加_isVue
属性,并设置其值为true
。看注释知道是为了避免被响应系统观察,也就是说,如果一个对象拥有_isVue
属性并且值为true
,那么就代表该对象是Vue
实例,这样就可以避免被观察。接下来是一个
options && options._isComponent
判断,它是用来初始化内部组件用到的,这块内容等讲到组件部分再来分析,所以先看else
部分。在
Vue
实例上添加了$options
属性,在官方文档中,我们也能看到它是用于当前Vue
实例的初始化选项,它是通过mergeOptions
函数创建而来。该函数有三个参数,第一个是通过函数resolveConstructorOptions
返回得到,第二个是调用Vue
构造函数时透传进来的对象,第三个参数是当前的Vue
实例。在讲
mergeOptions
前,我们先来看下resolveConstructorOptions
函数,看名字应该是用来解析构造函数的options
,传的参数也是实例的构造函数。看下具体实现:通过上面调用时传递的参数
vm.constructor
知道,这里的Ctor
是当前实例的构造函数,也就是Vue
本身。那么这里一定是Vue
吗?通过下面if
判断中的super
知道,Ctor
也有可能是个子类,因为只有之类才有super
属性。也就是说Ctor
有可能是通过Vue.extend
创造的一个子类。有了上面的理解,下面的
if
判断也比较好理解了。如果当前是Vue
的实例,那么直接返回Vue.options
的值。根据前面文章构造函数篇章知道,Vue.options
的值是通过全局global-api
来初始化的,内容如下:那么如果当前是子类的实例呢?
通过递归调用
resolveConstructorOptions
来获取父类的options
。而
Ctor.superOptions
的值我们前面的文章 Vue.extend 中提到也就是说它是通过
Vue.extend
继承而来的父类的静态属性options
值。当
superOptions
和cachedSuperOptions
不相等时,更新Ctor.superOptions
。这种情况比如如下例子:因为在执行
Vue.mixin
时,修改了Vue.options
的值:如果没有这个
if
判断,页面将只显示aka
,因为Vue.options
上的值还是旧的。接下来通过
resolveModifiedOptions
方法来检测“自身”的options
是否发生变化,如果有变化,返回修改的值。Ctor.extendOptions
作为传递给Vue.extend
的参数,和superOptions
合并并赋值给options
,最终返回options
。小结
上面说了这么多,似乎都是和
options
有关。而且后面的内容,都会使用到这个options
。既然options
这么重要,我们下一篇来说说options
的合并策略mergeOptions
函数是怎么实现的。参考
The text was updated successfully, but these errors were encountered: