vuex的作用
官方
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
个人理解
简单来说当我们使用 vue 进行项目开发的时候往往会遇到多个组件共享状态的情况,它们的关系有可能是父子、兄弟、爷孙甚至嵌套的更深,此时就使得状态难以管理,因此 vuex 应用而生,他就相当于一个仓库,存放需要共享的状态,并设置了一些方法可以更改、获取状态。(将就着看看,手笨)
简单介绍
1.State仓库,vuex使用单一状态树,每一个应用最好仅包含一个store实例,不建议直接修改state的值,最好是通过commit方法调用mutation任务进行修改,方便后期数据的追踪;
2.Mutations,定义方法动态修改state中的数据,不建议包含逻辑业务处理,处理一些同步任务;
3.Actions,定义方法执行异步任务一些复杂的逻辑代码,view层通过store.dispath分发Action任务;
4.Getter,类似vue实例中的计算属性特点,用来过滤、规范、改造数据;
5.Module,项目特别复杂的时候使用,每一个模块拥有自己的state,mutation,Action,getter,代码逻辑更加清晰;库内的数据。
vuex的用法
1.先新建一个文件引入 Vuex,Vue, 然后使用 Vue.use(Vuex) 注册组件。
2.再暴露实例化的一个Store类。
3.在 main.js 中引入,在实例化 Vue 的时候作为参数传入。
所以我们在模拟 vuex 功能写代码时需要暴露 install 函数 (Vue.use(Vuex)会自动调用 Vuex 的 install 方法安装插件) 和 Store类。
import Vue from 'vue'
import Vuex from '../vuex'Vue.use(Vuex)
export default new Vuex.Store({namespaced: true,state: {},getters: {},mutations: {},actions: {},modules: {}
})
一点思考
开始撸代码前先想一想最简单的 vuex 是怎么工作的呢?使用过 vuex 的同学知道,我们可以将状态及状态的操作方法分别配置在多个文件中,但最后在使用的的时候都可以通过 this.$store.state.xxx 访问状态、dispatch 触发 action 方法、 commit 触发 mutations 方法等等。而且其他文件中的配置与 Store 类的配置一致。由此可以联想到 vuex 简单使用是将多个文件中的配置都合并到了 Store 类上作为配置使用。
开始实现
暴露 Store 类和 install 方法
还记得前面说过什么吗?vuex 要暴露 Store 类和 install 方法。 index.js
import { Store, install } from './store';
export default {Store,install
}
forEach 工具函数
可以看到在文件开头引入了 forEach,它是我们写的一个工具函数,作用是遍历一个对象中的所有的属性,并返回该函数的属性名和属性值。
export const forEach = (obj = {}, fu) => {Object.keys(obj).forEach(key => fu(obj[key], key))
}
核心部分
下面是vuex的核心部分,定义了 Store 类和 install方法。
Store 类
Store类的构造函数中会分别调用工具函数 forEach 将传入的 getters、mutattions、actions 添加到对象上。同时定义 commit 函数,使实例可以调用 mutatiaons 中的方法,定义 dispatch 函数,使实例可以调用 actions 中的方法。
重点
- Vuex 是通过 new 一个 vue 实例,并把 state 作为 vue 的 data 利用 vue 的响应式系统把 state 中的数据变为了 响应式数据。* **getter 本质上是依赖了 vue 的 computed 实现了缓存机制。**store.js
import { forEach } from "./util";
import applyMixin from "./mixin";
let Vue;
class Store{constructor(options) {// 保存gettersthis.getters = {};const computed = {};// 遍历得到所有gettersforEach(options.getters, (fu, fuName) => { // 增加缓存机制computed[fuName] = () => {return fu(this.state);}Object.defineProperty(this.getters, fuName, {get: () => this._vm[fuName]})})// 发布订阅者模式,将用户定义的mutation和actions先保存起来,当调用commit十九调用订阅的mutation,调用dipatch时就调用订阅actionthis._mutations = {};forEach(options.mutations, (fu, fuName) => {this._mutations[fuName] = (payload) => fu.call(this, this.state, payload);})this._actions = {};forEach(options.actions, (fu, fuName) => {this._actions[fuName] = (payload) => fu.call(this, this, payload);})// 让数据变为响应式this._vm = new Vue({data: {//内部状态$$state: options.state},computed //计算属性会将自己的属性放到实例上})}// 可以使用本方法调用订阅的actions方法dispatch = (fuName, payload) => {this._actions[fuName](payload);} // 可以使用本方法调用订阅的mutation方法commit = (fuName, payload) => {this._mutations[fuName](payload);}// 类的属性访问器,当访问这个实例的state属性时会执行此方法get state() {return this._vm._data.$$state;}
}
// 定义的install方法
const install = (_Vue) => {Vue = _Vue;applyMixin(Vue);
}
export {Store,install
}
install 方法
在上面的文件中还定义了 install 方法,该方法在执行 Vue.use(Vuex) 时会自动调用,install 方法中主要是调用 mixin 方法,在 beforeCreate 勾子中为每个组件都混入一个$store
属性,他们都指向同一个 $store
实例。这样就可以通过 this.$store
拿到同一个实例达到数据共享的目的。
mixin.js
const applyMixin = (Vue) => {Vue.mixin({// 每个组件都会混入beforeCreate函数定义一个$store属性,指向同一个SotrebeforeCreate() {// 如果是根组件就为根组件添加$store属性if (this.$options && this.$options.store) {this.$store = this.$options.store;} else {// 如果是子组件就将根组件的$store属性值赋值给当前组件的$store属性this.$store = this.$parent && this.$parent.$store;}}})
}
export default applyMixin;
最后
整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。
有需要的小伙伴,可以点击下方卡片领取,无偿分享