实现观察者模式
手写 JavaScript 观察者模式
问题
实现观察者模式(发布-订阅模式),支持订阅、取消订阅和发布事件。
解答
基础实现
class EventEmitter {
constructor() {
// 存储事件和对应的回调函数列表
this.events = {};
}
// 订阅事件
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
return this; // 支持链式调用
}
// 取消订阅
off(event, callback) {
if (!this.events[event]) return this;
if (!callback) {
// 没传回调则移除该事件所有监听
delete this.events[event];
} else {
// 移除指定回调
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
return this;
}
// 发布事件
emit(event, ...args) {
if (!this.events[event]) return this;
this.events[event].forEach(callback => {
callback.apply(this, args);
});
return this;
}
// 只订阅一次
once(event, callback) {
const wrapper = (...args) => {
callback.apply(this, args);
this.off(event, wrapper); // 执行后立即移除
};
this.on(event, wrapper);
return this;
}
}
使用示例
const emitter = new EventEmitter();
// 订阅事件
function handleMessage(data) {
console.log('收到消息:', data);
}
emitter.on('message', handleMessage);
emitter.on('message', (data) => {
console.log('另一个监听器:', data);
});
// 发布事件
emitter.emit('message', { text: 'Hello' });
// 输出:
// 收到消息: { text: 'Hello' }
// 另一个监听器: { text: 'Hello' }
// 取消订阅
emitter.off('message', handleMessage);
emitter.emit('message', { text: 'World' });
// 输出:
// 另一个监听器: { text: 'World' }
// 只订阅一次
emitter.once('login', (user) => {
console.log('用户登录:', user);
});
emitter.emit('login', 'Tom'); // 输出: 用户登录: Tom
emitter.emit('login', 'Jerry'); // 无输出,监听器已移除
关键点
- 用对象存储事件名到回调数组的映射
on添加回调到数组,off从数组中移除emit遍历执行所有回调,用apply传递参数once通过包装函数实现执行后自动移除- 返回
this支持链式调用
目录