Vuex
注册插件和 route 一样,就不谈了
构造函数
constructor (options = {}) {
// Auto install if it is not done yet and `window` has `Vue`.
// To allow users to avoid auto-installation in some cases,
// this code should be placed here. See #731
/*
在浏览器环境下,如果插件还未安装(!Vue即判断是否未安装),则它会自动安装。
它允许用户在某些情况下避免自动安装。
*/
if (!Vue && typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
if (process.env.NODE_ENV !== 'production') {
assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)
assert(this instanceof Store, `Store must be called with the new operator.`)
}
const {
/*一个数组,包含应用在 store 上的插件方法。这些插件直接接收 store 作为唯一参数,可以监听 mutation(用于外部地数据持久化、记录或调试)或者提交 mutation (用于内部数据,例如 websocket 或 某些观察者)*/
plugins = [],
/*使 Vuex store 进入严格模式,在严格模式下,任何 mutation 处理函数以外修改 Vuex state 都会抛出错误。*/
strict = false
} = options
/*从option中取出state,如果state是function则执行,最终得到一个对象*/
let {
state = {}
} = options
if (typeof state === 'function') {
state = state()
}
// store internal state
/* 用来判断严格模式下是否是用mutation修改state的 */
this._committing = false
/* 存放action */
this._actions = Object.create(null)
/* 存放mutation */
this._mutations = Object.create(null)
/* 存放getter */
this._wrappedGetters = Object.create(null)
/* module收集器 */
this._modules = new ModuleCollection(options)
/* 根据namespace存放module */
this._modulesNamespaceMap = Object.create(null)
/* 存放订阅者 */
this._subscribers = []
/* 用以实现Watch的Vue实例 */
this._watcherVM = new Vue()
// bind commit and dispatch to self
/*将dispatch与commit调用的this绑定为store对象本身,否则在组件内部this.dispatch时的this会指向组件的vm*/
const store = this
const { dispatch, commit } = this
/* 为dispatch与commit绑定this(Store实例本身) */
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload)
}
this.commit = function boundCommit (type, payload, options) {
return commit.call(store, type, payload, options)
}
// strict mode
/*严格模式(使 Vuex store 进入严格模式,在严格模式下,任何 mutation 处理函数以外修改 Vuex state 都会抛出错误)*/
this.strict = strict
// init root module.
// this also recursively registers all sub-modules
// and collects all module getters inside this._wrappedGetters
/*初始化根module,这也同时递归注册了所有子module,收集所有module的getter到_wrappedGetters中去,this._modules.root代表根module才独有保存的Module对象*/
installModule(this, state, [], this._modules.root)
// initialize the store vm, which is responsible for the reactivity
// (also registers _wrappedGetters as computed properties)
/* 通过vm重设store,新建Vue对象使用Vue内部的响应式实现注册state以及computed */
resetStoreVM(this, state)
// apply plugins
/* 调用插件 */
plugins.forEach(plugin => plugin(this))
/* devtool插件 */
if (Vue.config.devtools) {
devtoolPlugin(this)
}
}Store 的构造类除了初始化一些内部变量以外,主要执行了 installModule(初始化 module)以及 resetStoreVM(通过 VM 使 store“响应式”)。
forEachValue(wrappedGetters, (fn, key) => {
// use computed to leverage its lazy-caching mechanism
computed[key] = () => fn(store)
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})resetStoreVM 首先会遍历 wrappedGetters,使用 Object.defineProperty 方法为每一个 getter 绑定上 get 方法,这样我们就可以在组件里访问 this.$store.getters.test 就等同于访问 store._vm.test。
store._vm = new Vue({
data: {
$$state: state
},
computed
})之后 Vuex 采用了 new 一个 Vue 对象来实现数据的“响应式化”,运用 Vue.js 内部提供的数据双向绑定功能来实现 store 的数据与视图的同步更新。