JAVASCRIPT中的常用设计模式
单例模式、构造原型设计模式、发布订阅模式、promise实际模式
学习设计模式的作用
开发层次
- 开发效率高
- 利于团队协作
维护层次
- 有利于代码的升级改版
- 逻辑清晰,代码严谨,有利于后期的维护
通用层次
- 依托设计模式我们可以实现组件化,模块化、插件化、框架化以及一些常用方法类库的编写
插件、类库、组件、框架的区别
- 类库:提供开发中常用的方法,方便我们开发和维护(jQuery、zepto);
- 插件:把项目中某一部分进行插件封装(具备具体的业务逻辑,更加有针对性例如轮播图,选项卡)以后再有类似的需求,直接导入即可,相关业务逻辑代码不需要自己编写【jQuery.drag.js/jQuery.dialog.js/jQuery.banner.js/jQuery.validate.min.js/datepicker日历插件,echarts统计图插件】
- 组件:类似于插件,但插件一般只封装js部分,组件不仅封装了JS,还封装了CSS,【swiper组件,bootstrap组件…】
- 框架:比上面的三个都庞大,不仅提供了很多常用方法,也可以支持一些插件的扩展,可以吧一些插件集成到框架中运行,更重要的是提供了非常优秀的设计思想【react/vue/reactnative/….】
单例设计模式
把实现这个模块所有的属性方法汇总到一个命名空间下(分组作用,避免全局污染);
真实项目中实现具体的业务逻辑需求可以依托于单例模式构建,将项目划分为各大板块或模块,把实现同一板块的方法放在一个独立的命名空间下;方便团队协作开发
构造原型模式:最贴近oop面向编程思想的
以后真实项目中,不管是封装类库还是插件,基本上都是基于构造原型模式来开发的;
class Tool{
constructor(){
this.isCompatible='addEventListener'in document;//判断兼容
//给实例提供的方法
}
css(){
// 挂载到原型上的方法
};
static distinct(){
//挂载到普通对象上的方法;
}
}
class Banner extends Tool{
constructor(...arg){
super();
this.xxx=xxx;
}
//挂在子类原型上的方法;
bindData(){
this.css();//把父类原型上的方法执行,(子类继承父类,那么子类的实例就可以调取父类原型上的方法以及父类给实例提供的私有属性方法)
this.distinct===undefined;//父类作为普通对象的方法,子类实例无法调用
}
}
发布订阅设计模式:(俗称:观察者模式)
》>不同于单例和构造,发布订阅是小型设计模式,凡是到达某个条件后,要执行N个方法,我们都可以依托于发布订阅模式管理和规划我们 的JS代码
我们经常把发布订阅模式嵌套到其他的设计模式中
promise设计模式
解决AJAX异步请求层级嵌套的问题,
他也是小型设计模式,目的就是为了解决层级嵌套的问题;我们经常把它嵌套到其他的设计模式中
- 发布订阅模式实现的思路和原理
- 创建一个容器(计划表);
- 后期需要做什么事情,我们都依次把需要处理的事情添加到计划表当中;
- 当符合某天个条件的时候,我们只需要通知计划表中的方法按照顺序依次执行即可;
jQ中的发布订阅
在jQ中提供了实现发布订阅设计模式的方法
let $plan=$.callbacks();//创建一个计划表
let fn= function () {};
$plan.add(fn);//向计划表中增加方法
$plan.remove(fn);//从计划表中移除方法
$plan.fire(100);//通知计划表所有的方法依次执行,100会分别传给每一个要执行的方法
我们自己基于ES6封装一个发布订阅模式库
1、基于构造函数封装
2、模拟JQ的操作步骤
3、注意数组塌陷问题
4、封装EACH遍历数组中的每一项
(function () {
//each:用来遍历数组中的每一项
let each = function (ary, callBack) {
for (let i = 0; i < ary.length; i++) {
let result = callBack && callBack(ary[i], i);
if (result === false) break;//如果执行的回调函数中返回false,代表结束当前遍历操作,(仿照JQ中的each语法实现的)
if(result='del') i--;//如果回调函数返回的是del,代表当前这一项在回调函数中被删除了。为了防止数组塌陷问题,我们得让索引
}
};
class plan {
constructor() {
this.planList = [];//存方法的实例
}
//原型上的方法
add(fn) {
let planList = this.planList;
flag = true;
//去重处理
each(planList, function (item, index) {
if (item === fn) {
flag = false;
return flag;
}
});
flag ? planList.push(fn) : null;
}
remov(fn) {
let planList = this.planList;
each(planList, function (item, index) {
if (item === fn) {
planList[index] = null;//删除会引起数组塌陷,这样处理索引不变
return false;
}
});
}
fire(...arg) {
let planList = this.planList;
each(planList, function (item, index) {
if (item === null) {
//当前项是已经被移除的
planList.splice(index, 1);
return 'del';
}
item(...arg);
});
}
//plan对象上的方法
static callbacks() {
return new plan();
}
}
})();