订阅发布模式和EventEmitter
Node中的EventEmitter,以及Vue的双向绑定,还有DOM2的事件监听方法都采用了发布订阅模式,所以我们动手实现一下,达成如下效果:
var emitter = new EventEmitter();
function handleOne(a, b, c) {
console.log('第一个监听函数', a, b, c)
}
function handleSecond(a, b, c) {
console.log('第二个监听函数', a, b, c)
}
function handleThird(a, b, c) {
console.log('第三个监听函数', a, b, c)
}
emitter.on("demo", handleOne)
.once("demo", handleSecond)
.on("demo", handleThird);
emitter.emit('demo', [1, 2, 3]);
// => 第一个监听函数 1 2 3
// => 第二个监听函数 1 2 3
// => 第三个监听函数 1 2 3
emitter.off('demo', handleThird);
emitter.emit('demo', [1, 2, 3]);
// => 第一个监听函数 1 2 3
emitter.allOff();
emitter.emit('demo', [1, 2, 3]);
// nothing
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- 每次调用方法则
return this
实现链式调用 once
表示只触发一次on
表示监听某个事件emit
触发这个事件off
表示不监听某个事件alloff
表示移除所有事件
实现方式:
class EventEmitter {
constructor() {
this._Events = new Map();
}
on(type, handler) {
if (this._Events.has(type)) {
this._Events.get(type).push({
listener: handler,
once: false
});
} else {
this._Events.set(type, [
{
listener: handler,
once: false
}
]);
}
return this;
}
once(type, handler) {
if (this._Events.has(type)) {
this._Events.get(type).push({
listener: handler,
once: true
});
} else {
this._Events.set(type, [
{
listener: handler,
once: true
}
]);
}
return this;
}
off(type, handler) {
if (this._Events.has(type)) {
let index = this._Events.get(type).findIndex(item => {
return item.listener === handler;
});
this._Events.get(type).splice(index, 1);
}
return this;
}
emit(type, ...args) {
if (this._Events.has(type)) {
this._Events.get(type).forEach(item => {
item.listener.apply(this, ...args);
});
this._Events.set(type, this._Events.get(type).filter(item => !item.once));
}
return this;
}
allOff() {
this._Events = new Map();
return this;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
JS用过的几种设计模式:
(1)单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
实现方法:先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。
适用场景:一个单一对象。比如:弹窗,无论点击多少次,弹窗只应该被创建一次。
(2)发布/订阅模式 定义:又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
场景:订阅感兴趣的专栏和公众号。
(3)策略模式 定义:将一个个算法(解决方案)封装在一个个策略类中。
优点:
- 策略模式可以避免代码中的多重判断条件。
- 策略模式很好的体现了开放-封闭原则,将一个个算法(解决方案)封装在一个个策略类中。便于切换,理解,扩展。
- 策略中的各种算法可以重复利用在系统的各个地方,避免复制粘贴。
- 策略模式在程序中或多或少的增加了策略类。但比堆砌在业务逻辑中要清晰明了。
- 违反最少知识原则,必须要了解各种策略类,才能更好的在业务中应用。
应用场景:根据不同的员工绩效计算不同的奖金;表单验证中的多种校验规则。
(4)代理模式
定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。
应用场景:图片懒加载(先通过一张loading图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img标签里面。)
(5)中介者模式
定义:通过一个中介者对象,其他所有相关对象都通过该中介者对象来通信,而不是互相引用,当其中的一个对象发生改变时,只要通知中介者对象就可以。可以解除对象与对象之间的紧耦合关系。
应用场景: 例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等等,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。
(6)装饰者模式
定义:在不改变对象自身的基础上,在程序运行期间给对象动态的添加方法。
应用场景: 有方法维持不变,在原有方法上再挂载其他方法来满足现有需求;函数的解耦,将函数拆分成多个可复用的函数,再将拆分出来的函数挂载到某个函数上,实现相同的效果但增强了复用性。
← web性能优化 动手实现一个简单的MVVM →