Codog

关注微信公众号:Codog代码狗

0%

简易Event Emitter实现

Event Emitter也是一个高频面试题目,满足事件订阅、取消、订阅一次,新手实现需要一些时间,总结下来逻辑并不复杂,这里使用class方式实现。

1
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
class EventEmitter {
constructor() {
// 记录所有事件即处理函数
this.events = {};
}
on(event, listener) {
// 一个事件可能注册多个处理函数,所以初始值设置为空数组
if (typeof this.events[event] !== 'object') {
this.events[event] = [];
}
this.events[event].push(listener);
// 返回值为取消订阅函数,调用该返回值,也可以手动执行removeListener方法
return () => this.removeListener(event, listener);
}
removeListener(event, listener) {
if (typeof this.events[event] === 'object') {
// 遍历处理函数数组,并移除
const idx = this.events[event].indexOf(listener);
if (idx > -1) {
this.events[event].splice(idx, 1);
}
}
}
emit(event, ...args) {
if (typeof this.events[event] === 'object') {
// 每个事件的处理函数都执行一遍
this.events[event].forEach(listener => listener.apply(this, args));
}
}
once(event, listener) {
// 实际上在内部执行了on方法,只是在调用处理函数时取消订阅
const remove = this.on(event, (...args) => {
remove();
listener.apply(this, args);
});
}
};

测试代码:

1
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
function handler1() {
console.log('handle1...', arguments)
}

function handler2() {
console.log('handler2...', arguments)
}

function handler3(data) {
console.log('handler3...', data)
}
const EE = new EventEmitter()

// 注册订阅时,要指向同一个函数变量,否则会导致无法取消,因为那样的写法实际是一个新方法
EE.on('evt1', handler1)
EE.on('evt1', handler3)

EE.emit('evt1', 1,2,3)
EE.emit('evt1', 4,5)
EE.removeListener('evt1', handler1)

EE.emit('evt1', 6)

EE.once('evt2', handler2)

EE.emit('evt2')
EE.emit('evt2')

执行结果:

image

这样基本功能就实现了,由于使用class方式,所以实际使用时需要考虑兼容性。

代码参考自:https://gist.github.com/mudge/5830382