解析 vuex.Store

2/28/2021 Vuex

# 看看 Store 整个构造函数的声明

var Vue; // bind on install
var Store = function Store(options) {
    var this$1 = this;
    if (options === void 0) 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
    
    if (!Vue && typeof window !== 'undefined' && window.Vue) {
        install(window.Vue);
    }
    {
        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.");
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

在第二个 if 判断我们可以看到,如果 vuex 内部的 Vue 变量没有绑定 vue 的话,Store 初始化也会自动注入。

this._committing = false;                   // flag state 只能被 mutation 修改,在严格模式下会报错
this._actions = Object.create(null);        // 存储所有的 actions 
this._actionSubscribers = [];               // 存储所有的 actions 订阅,
this._mutations = Object.create(null);      // 存储所有的 mutations 
this._subscribers = [];                     // 存储所有的 mutations 订阅,

this._wrappedGetters = Object.create(null);
this._modulesNamespaceMap = Object.create(null);    // 存放有 命名空间的 module
this._makeLocalGettersCache = Object.create(null);

this._watcherVM = new Vue();                        // 挂载 vue 实例,主要是利用 vue 一些全局的 api
this._modules = new ModuleCollection(options);      // 挂载所有的 state 模块, 包括 root 模块
1
2
3
4
5
6
7
8
9
10
11
12

对于 this 挂载的变量基本上都是要全部使用的,看到 Object.create(null); 赋值的变量,基本上都是用于键值存储的,值得注意的是 this._modules, 这是由 new ModuleCollection(options) 实例化而来, this._watcherVM 同样如此。

var store = this; 
var ref = this;

var dispatch = ref.dispatch;
var commit = ref.commit;

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)
};
1
2
3
4
5
6
7
8
9
10
11
12
13

可以看到,将当前实例化的对象this分别赋值给两个变量 storeref,获取到原型链上的dispatchcommit方法,

this.strict = strict;

var state = this._modules.root.state;

installModule(this, state, [], this._modules.root);

resetStoreVM(this, state);

// 加载插件
plugins.forEach(function (plugin) {
    return plugin(this$1);  // this$1 === store === this
});

var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;

if (useDevtools) {
    devtoolPlugin(this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这部分主要是使用了 installModuleresetStoreVM 来初始化一些逻辑以及插件的加载,我们来看看这两个方法的具体实现。

function installModule(store, rootState, path, module, hot) {
    var isRoot = !path.length;
    var namespace = store._modules.getNamespace(path);

    // register in namespace map
    if (module.namespaced) {
        if (store._modulesNamespaceMap[namespace] && true) {
            console.error(("[vuex] duplicate namespace " + namespace + " for the namespaced module " + (path.join('/'))));
        }
        store._modulesNamespaceMap[namespace] = module;
    }

    // set state
    if (!isRoot && !hot) {
        var parentState = getNestedState(rootState, path.slice(0, -1));
        var moduleName = path[path.length - 1];
        store._withCommit(function () {
            {
                if (moduleName in parentState) {
                    console.warn(
                        ("[vuex] state field \"" + moduleName + "\" was overridden by a module with the same name at \"" + (path.join('.')) + "\"")
                    );
                }
            }
            Vue.set(parentState, moduleName, module.state);
        });
    }

    var local = module.context = makeLocalContext(store, namespace, path);

    module.forEachMutation(function (mutation, key) {
        var namespacedType = namespace + key;
        registerMutation(store, namespacedType, mutation, local);
    });

    module.forEachAction(function (action, key) {
        var type = action.root ? key : namespace + key;
        var handler = action.handler || action;
        registerAction(store, type, handler, local);
    });

    module.forEachGetter(function (getter, key) {
        var namespacedType = namespace + key;
        registerGetter(store, namespacedType, getter, local);
    });

    module.forEachChild(function (child, key) {
        installModule(store, rootState, path.concat(key), child, hot);
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
上次更新: 2/18/2025, 2:29:21 PM