手写发布订阅EventEmitter完整实现
请手写实现一个完整的EventEmitter(发布订阅模式),支持on/off/emit/once/事件名通配符。
回答
我是大山
class EventEmitter {
constructor() { this._events = {}; }
on(event, fn) {
if (!this._events[event]) this._events[event] = [];
this._events[event].push(fn);
return this;
}
off(event, fn) {
if (!this._events[event]) return this;
if (!fn) { delete this._events[event]; return this; }
this._events[event] = this._events[event].filter(f => f !== fn);
return this;
}
emit(event, ...args) {
(this._events[event] || []).forEach(fn => fn(...args));
if (event !== '*') (this._events['*'] || []).forEach(fn => fn(event, ...args));
return this;
}
once(event, fn) {
const wrapper = (...args) => {
fn(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
return this;
}
}
const bus = new EventEmitter();
bus.on('data', d => console.log('data:', d));
bus.once('init', () => console.log('init only'));
bus.emit('data', 42);
注意:once通过包装函数实现自动取消。