这是我参与「第四届青训营 」笔记创作活动的第2天
1、常见问题的解决方案模型
- 根据历史经验的总结
- 与特定语言无关
2、浏览器的设计模式
1. 单例
定义
全局唯一访问的对象,保证一个类在全局当中,只有一个实例对象,这种模式叫做单例
应用场景
缓存,全局状态管理等(例如咱们的 Vuex)
单例的实现方式
首先,课上给出「用单例模式实现请求缓存」如下图所示
然后我给出我对「单例模式」的实现步骤
- 我们得有一个类(
Single) ,它的功能就是创建实例对象,但是得在内部函数当中判断是否创建过对象 - 调用
Single的 static 方法创建实例,进入方法当中时对类是否创建过实例做个判断,第一次进入的方法才返回new Single,之后的都返回这个已经创建好的实例 - 所以咱们的实例得到的都是一个实例
话不多说,代码模拟一波~
class Single {
static getInstance() {
// 判断是否第一次创建实例
if (!Single.instance) {
Single.instance = new Single();
}
return Single.instance;
}
}
let sin1 = Single.getInstance();
let sin2 = Single.getInstance();
console.log(sin1 == sin2) // true
以上就是我们简单的单例模拟啦~其中的核心思想还是实现全局唯一访问的对象
2. 发布与订阅
定义
一种订阅机制,可以在被订阅对象发生变化时通知订阅者
应用场景
统架构之间的解耦,到业务中的实现模式,例如邮件订阅,上线订阅等
发布与订阅的实现方式
首先,课上给出「用发布与订阅模式实现用户上线订阅」如下图所示
其次,我对发布与订阅理解如下~
- 发布订阅的意义就是在于,使用一个中介(eventHub) 来事件的操控进行存储操作,类似于A泡妞的方法存储起来(on),B看到这本子就可以使用(emit),为了不给人看见,必要时候可以抹出(off)
- 所以我们得实现三个方法,
on是对同名的事件的存储,emit是触发同名事件的所有函数,off将函数出该名函数群中去除
实现步骤为:
- 首先得对事件有个存储,因为事件是按照添加的执行顺序执行,所以得使用队列这数据结构,同个名的函数,添加进queueMap任务队列当中,按照订阅的创建顺序所定,呈映射关系
- 在off当中,是在任务队列中找到fn是否存在,返回其索引值(index),再将其删除
- queeMap是在eventHub上的,调用时得加前缀
实现代码如下:
// 中间(存储发布与订阅)
const eventHub = {
// 存储任务队列的集合
queueMap: {},
// 订阅
on: (name, fn) => {
// 考虑name队列不存在的情况
// if (queueMap[name] !== undefined) {
// queueMap[name] = [];
// }
eventHub.queueMap[name] = eventHub.queueMap[name] || []; // 代替上面的,使用设计模式:防御式编程
eventHub.queueMap[name].push(fn); // 将事件名为name的队列,添加回调函数
// return undefined;
},
// 发布
emit: (name, data) => {
const q = eventHub.queueMap[name]; // alins缩写设计模式
// 先判断为name的队列是否存在
if (!q) { return } // 设计模式:短路(不存在直接return,省一个else)
q.map(fn => fn(data)); // 对其任务队列的任务,进行执行
// return undefined;
},
// 取消订阅(找到任务队列的指定任务,再把它ko掉)
off: (name, fn) => {
const q = eventHub.queueMap[name]; // alins缩写设计模式
if (!q) { return };
// 找到任务队列当中是否有fn
const index = q.indexOf(fn);
if (index < 0) { return }; // 没找到呀,直接返回
q.splice(index, 1); // 删除为fn的任务
return undefined;
},
}
eventHub.on('click', console.log); // 参数:方法名,回调函数
// 一段时间,发布函数
setTimeout(() => {
eventHub.emit('click', 'fuk'); // 参数:指定的方法,输入的值
}, 2000);
3、javascript 设计模式
1. 原型模式
定义
复制已有模式来创建新的对象,我们使用原型模式,是为了得到与构造函数(类)相对应的类型的实例、实现数据/方法的共享,并不像有些资料说的,目的是为了克隆
应用场景:
JS中对象创建的基本模式
2. 代理模式
定义
可自定义控制叹对原对象的访问方式,并且允许在更新前后做一些额外处理
应用场景
监控(代理 fetch ),代理工具,前端框架实现等等
3. 迭代器模式
定义
在不暴露数据类型的情况下访问集合中的数据
应用场景
数据结构中有多种数据类型,列表,树等,提供通用操作接口
4、前端框架中的设计模式
1. 代理模式
目的是实现它
2. 组合模式
定义
多个对象组合使用,也可以单个对象独立使用
应用场景
DOM,前端组件,文件目录,部门