手写发布订阅模式 EventEmitter
1.简介
最近发现好多大厂面试题里都有手写发布订阅模式 EventEmitter,原因是 vue 和 react 的非父子组件的通信就是靠他实现的,下面是一个简易版的 EventEmitter。
2.代码
1 | // 发布订阅模式 |
2 | class EventEmitter { |
3 | constructor() { |
4 | // 事件对象,存放订阅的名字和事件 如: { click: [ handle1, handle2 ] } |
5 | this.events = {}; |
6 | } |
7 | // 订阅事件的方法 |
8 | on(eventName, callback) { |
9 | if (!this.events[eventName]) { |
10 | // 一个名字可以订阅多个事件函数 |
11 | this.events[eventName] = [callback]; |
12 | } else { |
13 | // 存在则push到指定数组的尾部保存 |
14 | this.events[eventName].push(callback); |
15 | } |
16 | } |
17 | // 触发事件的方法 |
18 | emit(eventName, ...rest) { |
19 | // 遍历执行所有订阅的事件 |
20 | this.events[eventName] && |
21 | this.events[eventName].forEach(f => f.apply(this, rest)); |
22 | } |
23 | // 移除订阅事件 |
24 | remove(eventName, callback) { |
25 | if (this.events[eventName]) { |
26 | this.events[eventName] = this.events[eventName].filter( |
27 | f => f != callback |
28 | ); |
29 | } |
30 | } |
31 | // 只执行一次订阅的事件,然后移除 |
32 | once(eventName, callback) { |
33 | // 绑定的时fn, 执行的时候会触发fn函数 |
34 | const fn = (...rest) => { |
35 | callback.apply(this, rest) // fn函数中调用原有的callback |
36 | this.remove(eventName, fn) // 删除fn, 再次执行的时候之后执行一次 |
37 | } |
38 | this.on(eventName, fn) |
39 | } |
40 | } |
3.使用
1 | const event = new EventEmitter(); |
2 | |
3 | const handle = (...pyload) => console.log(pyload); |
4 | |
5 | event.on("click", handle); |
6 | |
7 | event.emit("click", 100, 200, 300, 100); |
8 | |
9 | event.remove("click", handle); |
10 | |
11 | event.once("dbclick", function() { |
12 | console.log("click"); |
13 | }); |
14 | |
15 | event.emit("dbclick", 100); |
参考链接