js实现emit
实现事件发射器(Event Emitter)的核心逻辑
事件发射器模式是观察者模式的实现,允许对象订阅和触发自定义事件。以下是基于原生JavaScript的实现方式:
基础实现方案
创建EventEmitter类,包含事件注册和触发功能:

class EventEmitter {
constructor() {
this.events = {};
}
on(eventName, listener) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(listener);
return this;
}
emit(eventName, ...args) {
const listeners = this.events[eventName];
if (listeners) {
listeners.forEach(listener => listener.apply(this, args));
}
return this;
}
off(eventName, listenerToRemove) {
const listeners = this.events[eventName];
if (listeners) {
this.events[eventName] = listeners.filter(
listener => listener !== listenerToRemove
);
}
return this;
}
}
高级功能扩展
增加一次性事件和错误处理能力:

class AdvancedEventEmitter extends EventEmitter {
once(eventName, listener) {
const onceWrapper = (...args) => {
listener.apply(this, args);
this.off(eventName, onceWrapper);
};
return this.on(eventName, onceWrapper);
}
prependListener(eventName, listener) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].unshift(listener);
return this;
}
removeAllListeners(eventName) {
delete this.events[eventName];
return this;
}
}
实际应用示例
const emitter = new AdvancedEventEmitter();
// 常规监听
emitter.on('data', (data) => {
console.log('Received data:', data);
});
// 一次性监听
emitter.once('connect', () => {
console.log('Connection established');
});
// 触发事件
emitter.emit('data', { id: 1, value: 'test' });
emitter.emit('connect');
emitter.emit('connect'); // 不会再次触发
性能优化建议
使用WeakMap存储私有事件数据避免内存泄漏:
const privateMap = new WeakMap();
class OptimizedEventEmitter {
constructor() {
privateMap.set(this, { events: {} });
}
_getEvents() {
return privateMap.get(this).events;
}
on(eventName, listener) {
const events = this._getEvents();
events[eventName] = events[eventName] || [];
events[eventName].push(listener);
return this;
}
}
浏览器兼容方案
为支持旧版浏览器提供ES5实现:
function LegacyEventEmitter() {
this.events = {};
}
LegacyEventEmitter.prototype.on = function(eventName, listener) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(listener);
};
LegacyEventEmitter.prototype.emit = function(eventName) {
var args = Array.prototype.slice.call(arguments, 1);
(this.events[eventName] || []).forEach(function(listener) {
listener.apply(this, args);
}.bind(this));
};






