JavaScript中可用原型链实现轻量级事件总线:构造函数初始化私有_events对象,on/emit/off等方法挂载在prototype上实现共享复用,确保实例间事件隔离且内存高效。

JavaScript 中可以用原型链模拟一个轻量级事件总线(Event Bus),核心思路是:让所有实例共享同一套事件注册、触发、移除方法,这些方法挂载在构造函数的 prototype 上,而事件存储(如回调列表)放在实例自身(this._events)中,避免跨实例污染。
定义 EventBus 构造函数和基础方法
先创建一个构造函数,并在它的原型上添加 on、emit、off 方法:
function EventBus() {
this._events = Object.create(null); // 每个实例独立维护事件映射
}
EventBus.prototype.on = function (type, handler) {
if (!this._events[type]) {
this._events[type] = [];
}
this._events[type].push(handler);
};
EventBus.prototype.emit = function (type, ...args) {
const handlers = this._events[type];
if (Array.isArray(handlers)) {
handlers.forEach(handler => handler(...args));
}
};
EventBus.prototype.off = function (type, handler) {
const handlers = this._events[type];
if (Array.isArray(handlers)) {
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
}
};
使用示例:多个实例互不干扰
因为 _events 是每个实例私有的,而方法来自原型,所以可以安全创建多个 EventBus 实例:
const bus1 = new EventBus();
const bus2 = new EventBus();
bus1.on('login', user => console.log('bus1 收到登录:', user));
bus2.on('login', user => console.log('bus2 收到登录:', user));
bus1.emit('login', { id: 1 }); // 只触发 bus1 的回调
// 输出:bus1 收到登录: { id: 1 }
bus2.emit('login', { id: 2 }); // 只触发 bus2 的回调
// 输出:bus2 收到登录: { id: 2 }
可选增强:支持 once(一次性监听)和通配符
可以在原型上继续扩展,比如增加 once 方法(内部调用 on + off):
立即学习“Java免费学习笔记(深入)”;
EventBus.prototype.once = function (type, handler) {
const onceHandler = (...args) => {
handler(...args);
this.off(type, onceHandler);
};
this.on(type, onceHandler);
};
若需简单通配符(如 '*' 监听所有事件),可在 emit 中补充逻辑:
- 触发
type对应的回调 - 检查是否存在
'*',有则一并执行 - 注意顺序和参数一致性(例如
['*']回调也接收相同...args)
为什么用原型链?关键优势
把方法挂在 prototype 上,而不是每次在构造函数里重新赋值给 this,好处包括:
- 节省内存:所有实例共享同一份函数引用,而非各自拷贝一份闭包
- 符合面向对象习惯:行为复用,状态隔离(
_events在实例上) - 便于后续统一升级:修改原型方法,所有已有实例立即生效


















