我们在安装完vuex后,需要通过new获取到store实例,即new Vuex.Store,这将立即执行constructor内的代码,对store初始化
首先定义了一堆初始值

接着定义commint和dispatch函数,这两个函数提供了连接mutations和actions的能力,这里进行重写主要是为了在组件中调用时this的指向是正确的

接着对store进行模块化处理,在实际业务中我们一般都是将store拆分以模块化管理,这对应配置对象的modules属性

在起初定义初始值的过程中,有获取到module实例,即

ModuleCollection为

首次执行逻辑,将通过new Module将模块中定义的值(state、getter、mutations、actions)挂载到_rawModule,将state提取到state上
向下,向实例上挂载root属性
当模块拆分的情况下,modules是有值的,并且在new Module过程中会被挂载到modules上,假设为{A:moduleA,B:moduleB},则遍历执行register,第一次的入参为[A],moduleA,false
第二次的new Module逻辑和首次一样
向下,本次的path有值,故走else逻辑,首先调用get方法

这将把首次保存的root作为初始值传入,对于本次而言,返回的是this.root,即上一次的module实例
接着执行parent.addChild,即this.root.addChild,这将向this.root._children下添加A值为moduleA

也就是说,vuex将根store作为root保存,通过_children属性保存子模块引用,以建立一颗module树。那么假设我们当前的配置如下

则this.modules如下

接着执行installModule,入参为store实例、[]、[]、module树,执行module的安装

namespace是在每个module中可选的属性,它将对我们每一个模块进行一次优化,比如在组件中使用dispatch('saveName'),那么在moduleA中实际上发送的将是dispatch('A/dispatch'),要达到这一效果,核心就是在makeLocalContext函数中

接着对我们模块中的属性进行处理,如mutation,这将调用并将registerMutation作为回调传入

由于在初始化过程中,已经将我们每个module经过Module类进行了处理,他们的每一级的_rowModule都是我们每一个子文件定义的值,对于根root而言,其实本次为空,但是对于A模块而言,将拿到值(saveName函数)
调用registerMutation,可以看出,vuex实际上是将我们的同名mutation保持在store实例上的_mutations数组中了,它们每一个的值都是一个匿名函数,即store.mutations.saveName=[fn]

对于actions和getter是也是一样的处理
回到installModule,将递归调用自身进行子模块的处理,对于子模块而言,将进入if逻辑

这将在Vue.set过程中,将state挂载到module中,此时我们的根store模块如下

接着调用resetStoreVM,这将建立一个类似事件中心的东西,负责响应式处理

最后,对插件进行处理

因此,初始化过程中,通过递归的方式将我们子module拆分挂载到根module上,它们的每一个值都是一个子模块引用。对于store而言,它最终将也将保持一份子mutation、getter、action的引用,它们的每一个key都是一个数组
