【模拟实现】EventEmitter
williamzhou 3/25/2021 面试模拟实现设计模式
# 原理
发布订阅模式
- emitter.on(name,fn) // 订阅name事件,监听函数为fn,可多次订阅
- emitter.once(name,fn) // 功能与on类似,但监听函数为一次性的,触发后自动移除
- emitter.emit(name,data1,data2,...,datan) // 发布name事件,所有订阅该事件的监听函数被触发,data1,…,datan作为参数传给监听函数,若有多个函数,按照顺序执行
- emitter.remove(name,fn) // 移除name事件的监听函数fn
# 代码实现
class EventEmitter {
constructor () {
this._cache = Object.create(null)
}
on (type, fn) {
this._cache[type] = this._cache[type] || []
const fns = this._cache[type]
if (fns.indexOf(fn) < 0) {
fns.push(fn)
}
return this
}
once (type, fn) {
const wrapFn = (...args) => {
fn.apply(this, args)
this.remove(type, wrapFn)
}
this.on(type, wrapFn)
return this
}
emit (type, ...args) {
const fns = this._cache[type]
if (Array.isArray(fns)) {
fns.forEach(fn => {
fn(...args)
})
}
return this
}
remove (type, fn) {
const fns = this._cache[type]
if (Array.isArray(fns)) {
if (fn) {
const idx = fns.indexOf(fn)
if (idx >= 0) {
fns.splice(idx, 1)
}
} else { // clear all binded functions
fns.length = 0
}
}
return this
}
}
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
38
39
40
41
42
43
44
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
# 测试一下
function fn1(a, b, c) {
console.log(a, b, c)
}
function fn2(a, b) {
console.log(a * 2, b * 3)
}
var em = new EventEmitter()
// 测试 on 和 emit
em.on('e1', fn1)
.on('e1', fn2)
.emit('e1', 1, 2, 3) // 1, 2, 3 2, 6
.emit('e1', 1, 2, 3) // 1, 2, 3 2, 6
console.log(em._cache.e1) // [fn1, fn2]
// 测试 once 和 emit
em.once('e2', fn1)
.once('e2', fn2)
.emit('e2', 3, 4, 5) // 3, 4, 5 6, 12
.emit('e2', 3, 4, 5) // 3, 4, 5
.emit('e2', 3, 4, 5) // 3, 4, 5
console.log(em._cache.e2) // []
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22