1.设计模式
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
个人理解它是一门方法论,告诉我们原理,我们可以灵活的去使用它,提高我们写代码时的复用率以及灵活性。
2.单例模式
设计模式,听起来挺高大上的,但我们日常开发中经常会使用到,只是我们不知道我们使用了设计模式而已。
比如,文章的主角--Vuex,一个典型的单例模式。
2.1 什么是单例模式
单例模式(Singleton Pattern)确保一个类只有一个实例,并提供一个访问它的全局访问点,这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
这个是Jvav的说法,通俗点的理解相当于。
在整个项目里创建了一个全局变量,项目里的组件都可以访问到这个全局变量,我们可以再组件中为这个全局变量赋值,加入函数,其他组件可以拿到这个值,使用函数,整个项目只有我一个全局变量,为单例。
为什么需要单例模式:
1.将“描述同一件事务的属性或者特征归纳汇总在一起”,同时避免全局变量污染。
2.模块块化开发之间数据的共享(状态管理)。
单例模式的优点:
1.对于频繁使用的对象,可以省略创建对象所花费的时间。
2.由于 new 操作的次数减少,对系统内存的使用频率也会降低。
3.全局唯一性,可以保证全局数据和功能的共享。
单例模式的缺点:
1.虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。
2.使用单例模式时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
常见的单例模式:
1.浏览器中的window对象。
2.小程序中的App对象.(getApp()方法其实就是获取唯一的App实例)。
3.类库中的全局对象,例如Vuex、Redux。
2.2 做个思考
我们每次调用 new 的时候,都会生成一个新的实例对象,每个实例对象之间是完全独立的。
function Feng(type) { this.grilFriend = type;}var grilFriend = Feng('萝莉')var grilFriend2 = Feng('御姐');console.log(grilFriend === grilFriend2) // false
那么怎么才能每次 new 都返回同一个实例对象呢?
肯定是有一个变量将第一次 new 生成的实例对象保存了下来,后面再执行 new 的时候,就直接返回第一次生成的实例对象,这样就实现了单例。
2.3 类实现
class GrilFriend{ constructor(){ this.name = '富婆'; } static getInstance() { if(!GrilFriend.instance) { GrilFriend.instance = new GrilFriend; } return GrilFriend.instance }}let grilFriend = GrilFriend.getInstance;let grilFriend2 = GrilFriend.getInstance;console.log(grilFriend === grilFriend2) // true
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
静态方法可以直接在父类上调用 GrilFriend.getInstance,而不是在实例对象上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。
用类来实现单例模式,只要记住这个 getInstance 静态方法就可以了。
2.4 闭包实现
var grilFriendTeam = function () { };
var grilFriend = (function () {
var instance;
return function () {
if (instance) {
return instance;
}
instance = new grilFriendTeam() return instance;
}
})();
var grilFriend1 = new grilFriend ();
var grilFriend2 = new grilFriend ();
console.log(grilFriend1 === grilFriend2) // true
借助闭包,在内存中保留了 instance 变量,不会被垃圾回收,用来保存唯一的实例,多次调用 new 的时候,只返回第一次创建的实例。
2.5 Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
如果在一个项目开发中频繁的使用组件传参的方式来同步data
中的值,一旦项目变得很庞大,管理和维护这些值将是相当棘手的工作。为此,Vue
为这些被多个组件频繁使用的值提供了一个统一管理的工具——VueX
。在具有VueX
的Vue项目中,我们只需要把这些值定义在VueX中,即可在整个Vue项目的组件中使用。
let Vue; //vue的构造函数
class ModuleCollection{
constructor(options){
this.register([],options);
}
//深度优先遍历
register(path,rootModule){
//1、定义一个新的子模块
let newModule = {
_raw: rootModule,
_children: {},
state: rootModule.state
}
//2、挂载根源模块
if(path.length === 0){
this.root = rootModule
}
//6、挂载子模块,将此时遍历到的模块挂载到对应父节点上,第二遍递归时才开始走这个判断
if(path.length != 0){
//7、根据path数组,找到rootModule此时对应的父节点
let parent = path.slice(0,-1).reduce((root,current) => {
return root._children[current];
},this.root);
//8、挂载至父节点
parent._children[path[path.length - 1]] = newModule;
}
//3、查询是否有子模块
if(rootModule.modules){
//4、对子模块进行遍历
forEach(rootModule.modules,(moduleName,module) => {
//5、对子模块进行递归处理
this.register(path.concat(moduleName),module);
})
}
}
}
class Store{
//用户传入options,我们首先的任务是将options中的属性和方法,绑定到store自身作用域上
constructor(options){
//先绑定state属性
this._s = new Vue({ //给state加上数据监听,使对应视图实时响应刷新
data: {
state: options.state
}
})
new ModuleCollection(options); //数据层级整理
//getters相当于computed
let getters = options.getters || {}
this.getters = {};
//再将getters属性中的各个方法绑定到this.getters的中,执行这些方法时自动传入state
Object.keys(getters).forEach((getterName => {
Object.defineProperties(this.getters,getterName,{
//此处使用箭头函数锁定this上下文,防止因调用者变化使this变更
get:()=>{
return getters[getterName](this.state);
}
})
}))
//mutations相当于method
let mutations = options.mutations || {}
this.mutations = {};
Object.keys(mutations).forEach(mutationName => {
//将私有属性mutations的方法绑定到实例属性this.mutations上
this.mutations[mutationName] = (preload) =>{
//执行私有属性mutations上对应的方法
mutations[mutationName](this.state,preload);
}
})
}
//用户的调用入口
commit = (type,payload) => {
this.mutations[type](payload);
}
//可以通过get、set控制state存取
get state(){
return this._s
}
}
const install = (_Vue) => {
Vue = _vue;
Vue.mixin({
//声明混入对象的声明周期,在每个组件创建之前加入store
beforeCreate(){
//判断父组件还是子组件,如果是子组件则把父组件的store传给子组件
if(this.$options && this.$options.store){
this.$store = this.$options.store
}else{
this.$store = this.$parent && this.$parent.$store
}
}
})
}
export default {
install, //vue.use方法在引入模块时,默认调用模块的install方法
Store
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!