手写发布订阅模式 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);

参考链接

1.https://www.fed123.com/javascriptnodejs/4681.html

2.https://www.jianshu.com/p/e0575e17de2a