vuex源码部分--store的构造函数

先贴一下store的构造函数

var Vue; // bind on install
// Store的构造类除了初始化一些内部变量以外,主要执行了installModule(初始化module)以及resetStoreVM(通过VM使store“响应式”)
var Store = function Store (options) {
  debugger
  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);
  }

  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.");
  }

  var plugins = options.plugins; if ( plugins === void 0 ) plugins = [];
  var strict = options.strict; if ( strict === void 0 ) strict = false;

  // store internal state
  /* 用来判断严格模式下是否是用mutation修改state的 */
  this._committing = false;
  this._actions = Object.create(null);
  this._actionSubscribers = [];
  this._mutations = Object.create(null);
  this._wrappedGetters = Object.create(null);
  // 根据options 收集 modules
  this._modules = new ModuleCollection(options);
  this._modulesNamespaceMap = Object.create(null);
  this._subscribers = [];
  this._watcherVM = new Vue();
  this._makeLocalGettersCache = Object.create(null);

  // bind commit and dispatch to self
  /*将dispatch与commit调用的this绑定为store对象本身,否则在组件内部this.dispatch时的this会指向组件的vm*/
  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)
  };

 // strict mode
 /*严格模式(使 Vuex store 进入严格模式,在严格模式下,任何 mutation 处理函数以外修改 Vuex state 都会抛出错误)*/
  this.strict = strict;

  var state = this._modules.root.state;

  // 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(function (plugin) { return plugin(this$1); });

  var useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools;
  if (useDevtools) {
    devtoolPlugin(this);
  }
};

大概说一下我现在对store构造函数的理解:
1.初始化了一些变量,如_actions,_mutaions等
2.执行了installModule(初始化module)
3.执行了resetStoreVM(通过VM使store“响应式”)

先来看看第一步,有哪些可圈可点的逻辑线!

this._modules = new ModuleCollection(options);
// rawRootModule 就是你new Vuex.store()里传入的options
var ModuleCollection = function ModuleCollection (rawRootModule) {
  // register root module (Vuex.Store options)
  this.register([], rawRootModule, false);
};

解读一下这个register方法

ModuleCollection.prototype.register = function register (path, rawModule, runtime) {
    var this$1 = this;
    if ( runtime === void 0 ) runtime = true;

  if (process.env.NODE_ENV !== 'production') {
    assertRawModule(path, rawModule);
  }

  var newModule = new Module(rawModule, runtime);
  if (path.length === 0) {
    this.root = newModule;
  } else {
    var parent = this.get(path.slice(0, -1));
    parent.addChild(path[path.length - 1], newModule);
  }

  // register nested modules
  if (rawModule.modules) {
    forEachValue(rawModule.modules, function (rawChildModule, key) {
      this$1.register(path.concat(key), rawChildModule, runtime);
    });
  }

这个方法里面,解读一下new Module这个方法

var newModule = new Module(rawModule, runtime);
var Module = function Module (rawModule, runtime) {
  this.runtime = runtime;
  // Store some children item
  this._children = Object.create(null);
  // Store the origin module object which passed by programmer
  this._rawModule = rawModule;
  var rawState = rawModule.state;

  // Store the origin module's state
  this.state = (typeof rawState === 'function' ? rawState() : rawState) || {};
};

所以,newModule这个对象的数据结构为

runtime: false
state: {sysmenu: null}
_children: {}
_rawModule: {state: {}, mutations: {}, actions: {}, modules: {}}
namespaced: (...)
__proto__: Object

其中_rawModule就是传入的options,继续回到store的构造函数里。这里生成的_modules在后面的installModule里会用到。
接着说store构造函数中第二点 installModule部分

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

  // register in namespace map
  /* 如果有namespace则在_modulesNamespaceMap中注册 */
  if (module.namespaced) {
    if (store._modulesNamespaceMap[namespace] && process.env.NODE_ENV !== 'production') {
      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 (process.env.NODE_ENV !== 'production') {
        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);
  });
}

贴一下相关数据结构好理解。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在store的构造函数中有一系列这种样式的代码,拿一个当做例子解读作用,这里forEachAction中的这个function,其实被当做参数fn传递给了下面贴出来的源码

  module.forEachAction(function (action, key) {
    var type = action.root ? key : namespace + key;
    var handler = action.handler || action;
    registerAction(store, type, handler, local);
  });
Module.prototype.forEachAction = function forEachAction (fn) {
// this._rawModule.actions 其实就是上面讲过的new Module里面生成的数据结构
  if (this._rawModule.actions) {
    forEachValue(this._rawModule.actions, fn);
  }
};

在这里插入图片描述
这里实际上就是对obj对象获取keys,遍历keys,调用fn(),而这个fn是上面用到的

function forEachValue (obj, fn) {
  Object.keys(obj).forEach(function (key) { return fn(obj[key], key); });
}

这里执行fn,实际上就是执行下面括号里面的方法

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

这里其实就是,判断actions是否有数据,如果有数据,就通过遍历,对每一个actions里面的数据调用上面的方法,即携带namespace参数,调用registerAction,结果就是在store上,_actions对象里有了数据。
执行完上述逻辑,初始化store时,传入的数据,包括有namespace的store都可以在_actions,_mutations中访问到了!
然后看第三个小点:resetStoreVM(this, state)

function resetStoreVM (store, state, hot) {
  var oldVm = store._vm;

  // bind store public getters
  store.getters = {};
  // reset local getters cache
  store._makeLocalGettersCache = Object.create(null);
  var wrappedGetters = store._wrappedGetters;
  var computed = {};
  forEachValue(wrappedGetters, function (fn, key) {
    // use computed to leverage its lazy-caching mechanism
    // direct inline function use will lead to closure preserving oldVm.
    // using partial to return function with only arguments preserved in closure environment.
    computed[key] = partial(fn, store);
    Object.defineProperty(store.getters, key, {
      get: function () { return store._vm[key]; },
      enumerable: true // for local getters
    });
  });

  // use a Vue instance to store the state tree
  // suppress warnings just in case the user has added
  // some funky global mixins
  var silent = Vue.config.silent;
  Vue.config.silent = true;
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed: computed
  });
  Vue.config.silent = silent;

  // enable strict mode for new vm
  if (store.strict) {
    enableStrictMode(store);
  }

  if (oldVm) {
    if (hot) {
      // dispatch changes in all subscribed watchers
      // to force getter re-evaluation for hot reloading.
      store._withCommit(function () {
        oldVm._data.$$state = null;
      });
    }
    Vue.nextTick(function () { return oldVm.$destroy(); });
  }
}

在这个方法里,两个核心:一个是将getters变成计算属性,resetStoreVM首先会遍历wrappedGetters,使用Object.defineProperty方法为每一个getter绑定上get方法,这样我们就可以在组件里访问this.$store.getters.test就等同于访问store._vm.test。另一个:new一个Vue对象来实现数据的“响应式化”,运用Vue.js内部提供的数据双向绑定功能来实现store的数据与视图的同步更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 安卓源码合集-csdn是一个非常有用的工具和资源网站,提供了大量的开源安卓项目源码供开发者学习和使用。 首先,这个合集汇集了来自开源社区的各种优秀的安卓项目源码。这些源码不仅涵盖了安卓开发的各个方面,如UI界面、网络通信、数据存储等,还有一些特定领域的应用,如音视频处理、图像处理、机器学习等。从这些源码中,开发者可以学习到各种技术和知识,拓宽自己的视野和开发能力。 其次,通过这个合集,开发者可以找到适合自己需求的开源项目源码。不同的项目可能有不同的功能和特点,可以根据自己的需求进行选择和使用。有些源码可能是完整的应用程序,可以直接使用或基于此进行二次开发;有些源码可能是某个功能模块的实现,可以作为学习参考或直接集成到自己的项目中。 此外,这个合集还提供了源码的下载和查看方式。开发者可以通过下载源码来进行学习和使用,也可以在线查看源码进行参考。对于一些比较复杂的项目,还提供了详细的项目文档和使用说明,方便开发者的使用和理解。 总的来说,安卓源码合集-csdn为开发者提供了一个集成了优秀开源项目源码的平台,为开发者学习和使用安卓开发技术提供了便利。无论是初学者还是有一定经验的开发者,都可以在这里找到适合自己的项目源码,提升自己的开发水平和能力。 ### 回答2: 安卓源码合集 -csdn 是一个在 CSDN 上收集和分享安卓开源项目的一个资源合集。CSDN(博客专区)是一个面向IT技术人员的专业社区平台,它提供了丰富的技术资源和社交交流的平台。 安卓源码合集 -csdn 这个资源合集汇集了众多优秀的安卓开源项目,包括应用程序源码、工具类库、框架和示例代码等。通过该合集,开发者们可以快速地找到他们感兴趣的项目,并获取源码用于学习和参考。 这个合集的优点在于它的更新频率高,可以及时收录最新的开源项目。同时,合集中的项目都经过精心筛选,保证了其质量和可靠性。此外,该合集还提供了搜索功能,开发者们可以根据关键词进行搜索,找到适合自己需求的项目。 使用安卓源码合集 -csdn,开发者们可以快速地找到自己需要的安卓开源项目,可以通过学习他人的代码,了解他们的实现思路和技术。对于新手开发者来说,这个合集也可以作为一个学习的平台,他们可以通过阅读和理解他人的代码,提高自己的编码能力。 总之,安卓源码合集 -csdn 是一个非常有用的资源合集,可以帮助开发者们快速找到优秀的安卓开源项目,提高自己的技术水平。无论是初学者还是资深开发者,都可以从中受益。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值