研究Vue源码也有一段时间,我发现如果不将研究过程记录下来,过两天就忘得差不多了,今天开始记录吧。

  首先从new一个Vue实例开始。

  1.进入Vue构造函数,判断是否是通过new调用的,如果不是则抛出警告,保()证Vue构造函数是通过new操作符调用的。

  2.执行初始化函数_init,该函数在initMixin函数里定义,vue.prototype._init = function(options){....}, initMixin函数在Vue构造生成之初就执行了一遍。

  3.进入_init函数内部,判断如果是components组件,则执行initInternalComponent方法,这里初始化根实例则进入mergeOptions方法进行选项合并。

  4.来看mergeOptions方法,该方法接收三个参数,分别为默认的选项配置,实例化时传入的选项配置,还有根实例本身,mergeOptions方法实现以下步骤:

    • 首先会进行components属性中的每个组件名校验,不能使用数字,下划线和$开头的组件变量名,不能使用html保留的标签名比如html,svg,p等。
    • 进行props属性的校验,当props为数组,会判断数组中每个元素是否为字符串,如果是,则将其转换为对象,如果元素不是字符串,则报错,如果props属性不为对象也不为数组,则报错。最后将结果存进一个空对象并赋值给props属性。
    • 进行inject属性的校验,无论inject为数组或者对象,最终都会将其元素转化为对象,不为数组或对象则报错。
    • 进行自定义指令的校验,如果directives属性里的属性名对应的值为函数时,则默认绑定到bind和update钩子。

  5.进行以上校验后,接下来就是各个选项属性的合并了,针对根实例选项与默认构造器选项的合并过程如下:

    • 对于component,directive,filter属性,先会对其值进行检测,如果值不是对象则报错,检测完后,如果父类无同名属性,则新增,反之则覆写。
    • 对于props,methods,inject,computed属性,同样要先保证其值为对象,如果父类对象中无同名属性,则新增,反之则覆写。
    • 对于provide属性,合并时返回mergedInstanceDataFn函数,该函数在调用时,如果provide属性为函数则直接调用,并对返回的对象进行合并,如果有嵌套对象则进行递归合并,如果子类对象无同名属性,则将父类属性添加到子类,最终返回子类对象。
    • 对于data属性,除了根实例外,其他子类的data属性必须是一个函数,否则报错,data合并逻辑同provide属性。
    • 对于生命周期钩子函数的合并,则会将父类和子类的相同钩子函数整合到同一个数组中,保持父类钩子在子类钩子前执行。
    • 对于watch合并,首先保证其值为对象,如果父类无watch对象,则返回子类watch对象,反之则返回父类watch对象,两者的watch中存在同名属性,则将父子类同名属性存进数组,保证父在子前的执行顺序。