一、设计模式
设计模式:
单例设计模式:解决了“全局变量污染”的问题、还可以保证模块间方法的相互访问 「最早的模块化开发的思想」工厂设计模式@1 其实就是利用“函数封装”的特点,把重复做的事情封装起来,实现“低耦合高内聚”:减少页面中冗余代码,提高代码重复使用率,提高开发效率等!
@2 在JQ源码中,基于工厂模式实现:把jQuery当做普通方法执行,也可以创造其一个实例构造函数设计模式:充分利用面向对象的思想,有效的实现了实例和实例之间的“独立性”以及“共有性”,适用于插件组件封装,例如:我们用的Swiper轮播图插件,Swiper本身就是一个类,每一次创建轮播图都是创造Swiper的一个实例!!Promise承诺者设计模式:基于promise和async/await可以有效管理异步编程的代码,防止回调地狱!!发布订阅设计模式观察者设计模式…
设计模式就是一种思想,基于这种思想可以有效的管理我们的代码;设计模式是“锦上添花”!! 二、发布订阅 1、发布订阅的实现方案
(function () {
class Sub {
// 给实例设置私有的事件池
listeners = [];
// 在原型上扩展add/remove/fire来管理事件池中的方法&通知方法执行
// 方法中的this一般指当前类的实例 -> s1.add/remove/fire(...)
add(func) {
let listeners = this.listeners;
if (listeners.includes(func)) return;
listeners.push(func);
}
remove(func) {
let listeners = this.listeners;
let index = listeners.indexOf(func);
if (index >= 0) {
listeners[index] = null;
}
}
fire(...params) {
let listeners = this.listeners;
for (let i = 0; i < listeners.length; i++) {
let item = listeners[i];
if (typeof item !== "function") {
listeners.splice(i, 1);
i--;
continue;
}
item(...params);
}
}
}
window.Sub = Sub;
})();
let s1 = new Sub;
let s2 = new Sub;
const fn1 = (x, y) => {
console.log('fn1', x, y);
};
const fn2 = (x, y) => {
console.log('fn2', x, y);
// 移除事件池
s1.remove(fn1);
s1.remove(fn2);
};
const fn3 = () => console.log('fn3');
const fn4 = () => console.log('fn4');
const fn5 = () => console.log('fn5');
const fn6 = () => console.log('fn6');
// 加入事件池
s1.add(fn1);
s1.add(fn2);
s1.add(fn3);
s1.add(fn4);
s1.add(fn5);
s1.add(fn6);
s2.add(fn4);
s2.add(fn5);
s2.add(fn6);
// 通知执行
setTimeout(() => {
s1.fire(100, 200);
// 再过一秒再执行
setTimeout(() => {
s1.fire(1000, 2000);
}, 1000);
}, 1000);
2、第二种实现方案
(function () {
// 创建计划表
const listeners = {};
// 向计划表某个计划中加入方法
const on = function on(name, func) {
// 首先校验“name”计划在计划表中是否存在,如果不存在,则先创建这样的计划,值是空数组
if (typeof listeners[name] === "undefined") {
listeners[name] = [];
}
// 获取该计划后面的数组集合
let arr = listeners[name];
// 每一次加方法执行先判断「该方法是否已经在集合中存在,不允许重复加入的」
if (arr.includes(func)) return;
// 把需要执行的方法加入到集合中
arr.push(func);
};
// 从计划表某个计划中移除方法
const off = function off(name, func) {
// 首先校验该计划是否存在
if (typeof listeners[name] === "undefined") return;
// 迭代数组中的每一项,移除对应的内容
let arr = listeners[name];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === func) {
// arr.splice(i, 1); //这样会导致数组塌陷
arr[i] = null; //不移除,数组的索引结构就不会变
break;
}
}
};
// 通知计划表中某个计划中的方法执行
const emit = function emit(name, ...params) {
if (typeof listeners[name] === "undefined") return;
// 迭代数组每一项,把每一项执行「不要忘记把接收的实参传递给每个函数」
let arr = listeners[name];
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (typeof item === "function") {
item(...params);
continue;
}
// 当前项不是个函数,我们把其移除「也要注意数组塌陷问题,但是先减减再加加,下一轮还是从此时的i开始」
arr.splice(i, 1);
i--;
}
};
// 暴露API
window["_plain"] = {
on,
off,
emit
};
})();
const fn1 = (x, y) => {
console.log('fn1', x, y);
};
const fn2 = (x, y) => {
console.log('fn2', x, y);
_plain.off('marry', fn1);
_plain.off('marry', fn2);
};
const fn3 = () => console.log('fn3');
const fn4 = () => console.log('fn4');
const fn5 = () => console.log('fn5');
const fn6 = () => console.log('fn6');
// 全部加入计划表
_plain.on('marry', fn1);
_plain.on('marry', fn2);
_plain.on('marry', fn3);
_plain.on('marry', fn4);
_plain.on('marry', fn5);
_plain.on('marry', fn6);
// 一秒后通知执行
setTimeout(() => {
_plain.emit('marry', 100, 200);
// 再过一秒再执行依次
setTimeout(() => {
_plain.emit('marry', 1000, 2000);
}, 1000);
}, 1000);
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)