vuex源码解析
首先我们先观察一下官方store实例的结构,然后再考虑按照它的结构实现一下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210702172230217.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NocmlzMTI5OQ==,size_16,color_FFFFFF,t_70#pic_center)
主要实现一个Store类和ModuleCollect类、以及helper辅助函数
Store类
// 1、插件:挂载$store
// 2、实现Store
// state的name与module名重复,state同名状态会被覆盖掉
import ModuleCollection from './ModuleCollection'
let Vue;
class Store {
constructor(options) {
// 所有的actions,包括子模块的actions
// {string:Array<function>}
this._mutations = {}
// 所有的actions,包括子模块的actions
// {string:Array<function>}
this._actions = {}
// 收集getters的初始容器,还没有实现响应式
// {string:function}
this._wrappedGetters = {}
// 命名空间与module的映射
// {string:module类}
this._modulesNamespaceMap = {}
// actions的插件订阅者
this._actionSubscribers = {}
// mutations的插件订阅者
this._subscribes = []
// getters
this.getters = {} // 需要借助vue的计算属性
// 把数据格式化成一个想要的树结构
this._modules = new ModuleCollection(options)
const state = this._modules.root.state
// 递归将结果进行分类
// this 整个store
// this.state 当前的根状态
// [] 为了递归来创建
// this.module.root 从根模块进行安装
installModule(this, state, [], this._modules.root)
// 将state变为响应式,并且把getters变为计算属性
resetStoreVm(this, state)
// 处理插件
options.plugins.forEach(plugin => plugin(this))
}
// 插件订阅mutations
subscribe(fn) {
this._subscribes.push(fn)
}
// 插件订阅actions
subscribeActions(fn) {
this._actionSubscribers.push(fn)
}
// 提交更改 会在当前的store上找到对应的函数执行
// 采用箭头函数就不需要绑定this了
commit = (mutationName, payload) => {
this._mutations[mutationName].forEach(fn => fn(payload))
}
// dispatch对应的action在当前的store上找到对应的函数执行
// 采用箭头函数就不需要绑定this了
dispatch = (actionName, payload) => {
this._actions[actionName].forEach(fn => fn(payload))
}
get state() {
return this._vm._data.$$state
}
set state(val) {
// 禁止用户直接改变state
throw new Error('不允许改变,请使用replaceState')
}
replaceState(state) {
this._vm._data.$$state = state
}
}
const install = (_Vue) => {
Vue = _Vue
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
},
})
}
// 迭代对象,会将对象的key与value拿到
function forEach(obj, cb) {
Object.keys(obj).forEach(key => {
cb(key, obj[key])
})
}
// 判断是否是对象
function isObject(obj) {
return obj !== null && typeof obj == 'object'
}
// 统一参数
function unifyObjectStyle(type,