发布订阅模式是我们在项目中常见的模式,也是面试中常考的手写题。
代码实现如下:
// 实现发布订阅模式
class EventEmitter {
// 1.定义事件容器,用来装事件数组
handlers = {}
// 2.添加事件方法,参数:事件名 事件方法 是否只执行一次
on(type, handler, once = false) {
if (!this.handlers[type]) {
this.handlers[type] = [];
}
if (!this.handlers[type].includes(handler)) {
this.handlers[type].push(handler);
handler.once = once;
}
}
// 3.触发事件方法,参数:事件名 事件方法
trigger(type, params) {
if (this.handlers[type]) {
this.handlers[type].forEach(handler => {
handler.call(this, params);
if (handler.once) {
this.off(type, handler)
}
});
} else {
return new Error('该事件未注册')
}
}
// 4.移除事件方法,参数:事件名 事件方法,若无第二个参数则删除该事件的订阅发布
off(type, handler) {
// 若没有注册该事件,则抛出错误
if (!this.handlers[type]) {
return new Error('事件无效')
}
// 移除事件
if (!handler) {
delete this.handlers[type]
} else {
this.handlers[type] = this.handlers[type].filter(h => h !== handler)
if (this.handlers[type].length === 0) {
delete this.handlers[type]
}
}
}
// 5.只执行一次事件方法,参数:事件名 事件方法,执行一次后自动删除
once(type, handler) {
this.on(type, handler, true)
}
}
const ev = new EventEmitter();
function handler1(a) {
console.log('handler1', ...a);
}
function handler2(a) {
console.log('handler2', ...a);
}
function handler3(a) {
console.log('handler3', ...a);
}
ev.on('test', handler1);
ev.on('test', handler2);
ev.on('test', handler3);
ev.trigger('test', [123, 456])