博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS每日一题: 请简述一下vuex实现原理
阅读量:7050 次
发布时间:2019-06-28

本文共 4521 字,大约阅读时间需要 15 分钟。

20190221

请简述一下vuex实现原理

对vuex基础概念有不懂的可以点

vuex实现原理我们简单过一遍源码 地址

首先我们例出几个问题进行思考

  • store是怎么注册的?
  • mutation,commit 是怎么实现的?
  • 辅助函数是怎么实现的?

store是怎么注册的

看了下面的源码就很清楚了, 我们看到vuex在vue 的生命周期中的初始化钩子前插入一段 Vuex 初始化代码。给 Vue 的实例注入一个 $store 的属性,这也就是为什么我们在 Vue 的组件中可以通过 this.$store.xxx 访问到 Vuex 的各种数据和状态

// 源码位置 https://github.com/vuejs/vuex/blob/665455f8daf8512e7adbf63c2842bc0b1e39efdb/src/mixin.jsexport default function (Vue) {  const version = Number(Vue.version.split('.')[0])  if (version >= 2) {    Vue.mixin({ beforeCreate: vuexInit })  } else {    // override init and inject vuex init procedure    // for 1.x backwards compatibility.    const _init = Vue.prototype._init    Vue.prototype._init = function (options = {}) {      options.init = options.init        ? [vuexInit].concat(options.init)        : vuexInit      _init.call(this, options)    }  }  /**   * Vuex init hook, injected into each instances init hooks list.   */  function vuexInit () {    const options = this.$options    // store injection    if (options.store) {      this.$store = typeof options.store === 'function'        ? options.store()        : options.store    } else if (options.parent && options.parent.$store) {      this.$store = options.parent.$store    }  }}

mutations,commit 是怎么实现的

// 源码位置  https://github.com/vuejs/vuex/blob/665455f8daf8512e7adbf63c2842bc0b1e39efdb/src/store.js#L417function registerMutation (store, type, handler, path = []) {  const entry = store._mutations[type] || (store._mutations[type] = [])  entry.push(function wrappedMutationHandler (payload) {    handler(getNestedState(store.state, path), payload)  })}

registerMutation 是对 store 的 mutation 的初始化,它接受 4 个参数,store为当前 Store 实例,type为 mutation 的 key,handler 为 mutation 执行的回调函数,path 为当前模块的路径。mutation 的作用就是同步修改当前模块的 state ,函数首先通过 type 拿到对应的 mutation 对象数组, 然后把一个 mutation 的包装函数 push 到这个数组中,这个函数接收一个参数 payload,这个就是我们在定义 mutation 的时候接收的额外参数。这个函数执行的时候会调用 mutation 的回调函数,并通过 getNestedState(store.state, path) 方法得到当前模块的 state,和 playload 一起作为回调函数的参数

我们知道mutation是通过commit来触发的,这里我们也来看一下commit的定义

// 源码位置 https://github.com/vuejs/vuex/blob/665455f8daf8512e7adbf63c2842bc0b1e39efdb/src/store.js#L82  commit (_type, _payload, _options) {    // check object-style commit    const {      type,      payload,      options    } = unifyObjectStyle(_type, _payload, _options)    const mutation = { type, payload }    const entry = this._mutations[type]    if (!entry) {      if (process.env.NODE_ENV !== 'production') {        console.error(`[vuex] unknown mutation type: ${type}`)      }      return    }    this._withCommit(() => {      entry.forEach(function commitIterator (handler) {        handler(payload)      })    })    this._subscribers.forEach(sub => sub(mutation, this.state))    if (      process.env.NODE_ENV !== 'production' &&      options && options.silent    ) {      console.warn(        `[vuex] mutation type: ${type}. Silent option has been removed. ` +        'Use the filter functionality in the vue-devtools'      )    }  }

commit 支持 3 个参数,type 表示 mutation 的类型,payload 表示额外的参数,根据 type 去查找对应的 mutation,如果找不到,则输出一条错误信息,否则遍历这个 type 对应的 mutation 对象数组,执行 handler(payload) 方法,这个方法就是之前定义的 wrappedMutationHandler(handler),执行它就相当于执行了 registerMutation 注册的回调函数

辅助函数

辅助函数的实现都差不太多,这里只讲解mapState

// 源码地址  https://github.com/vuejs/vuex/blob/665455f8daf8512e7adbf63c2842bc0b1e39efdb/src/helpers.js#L7export const mapState = normalizeNamespace((namespace, states) => {  const res = {}  normalizeMap(states).forEach(({ key, val }) => {    res[key] = function mappedState () {      let state = this.$store.state      let getters = this.$store.getters      if (namespace) {        const module = getModuleByNamespace(this.$store, 'mapState', namespace)        if (!module) {          return        }        state = module.context.state        getters = module.context.getters      }      return typeof val === 'function'        ? val.call(this, state, getters)        : state[val]    }    // mark vuex getter for devtools    res[key].vuex = true  })  return res})

mapState在调用了 normalizeMap 函数后,把传入的 states 转换成由 {key, val} 对象构成的数组,接着调用 forEach 方法遍历这个数组,构造一个新的对象,这个新对象每个元素都返回一个新的函数 mappedState,函数对 val 的类型判断,如果 val 是一个函数,则直接调用这个 val 函数,把当前 store 上的 state 和 getters 作为参数,返回值作为 mappedState 的返回值;否则直接把 this.$store.state[val] 作为 mappedState 的返回值

为了更直观的理解,我们看下最终mapState的效果

computed: mapState({    name: state => state.name,  })    // 等同于    computed: {    name: this.$store.state.name  }

关于JS每日一题

JS每日一题可以看成是一个语音答题社区

每天利用碎片时间采用60秒内的语音形式来完成当天的考题
群主在次日0点推送当天的参考答案

  • 注 绝不仅限于完成当天任务,更多是查漏补缺,学习群内其它同学优秀的答题思路

转载地址:http://fgpol.baihongyu.com/

你可能感兴趣的文章
[Linux学习]脚本文件名搜索
查看>>
菜鸟机器学习散点总结(三)
查看>>
Cocos Creator Animation 组件
查看>>
RH033读书笔记(1)-Lab2 Linux Usage Basics
查看>>
window对象 (浏览器对象模型)
查看>>
Loadrunner 关于参数赋值取值的操作
查看>>
C# 实现保留两位小数的方法
查看>>
Http协议4个新的http状态码:428、429、431、511;
查看>>
C#类型简述
查看>>
Go:字符串操作
查看>>
EXCEL 2010学习笔记 —— VLOOKUP函数 嵌套 MATCH 函数
查看>>
android graphics: 2D animation
查看>>
升级 python 2.6.6 系统到 2.7.10 版本
查看>>
start with connect by prior 递归查询用法
查看>>
OS X 10.11 安装Cocoapods
查看>>
MATLAB测试机器零阈值的大小
查看>>
Bootstrap3 栅格系统-列偏移
查看>>
【翻译】Ext JS 4之HelloWorld
查看>>
【Unity Shaders】Vertex Magic —— 访问顶点颜色
查看>>
javascript的with表示什么?
查看>>