javascript中可通过原型链让自定义对象继承事件监听能力,核心是将on、emit、off等方法挂载到eventemitter.prototype上,子类通过object.setprototypeof()或class extends继承,实现可复用的事件系统。

JavaScript 中可以通过原型链让自定义对象继承事件监听能力,核心是把 on、emit、off 等方法挂载到父级构造函数的 prototype 上,子类通过 Object.setPrototypeOf() 或构造函数继承(如 Child.prototype = Object.create(Parent.prototype))获得这些方法。
设计一个可复用的 EventEmitter 基类
先实现一个轻量级的事件中心,支持注册、触发、移除监听器:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
function EventEmitter() {
this._events = Object.create(null);
}
EventEmitter.prototype.on = function(type, listener) {
if (!this._events[type]) {
this._events[type] = [];
}
this._events[type].push(listener);
return this; // 支持链式调用
};
EventEmitter.prototype.emit = function(type, ...args) {
const listeners = this._events[type];
if (listeners && listeners.length) {
listeners.forEach(fn => fn.apply(this, args));
}
return this;
};
EventEmitter.prototype.off = function(type, listener) {
const listeners = this._events[type];
if (listeners) {
const index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
}
return this;
};
子类通过原型链继承事件能力
让业务类(如 Button、Modal)继承 EventEmitter 的原型方法,无需重复实现事件逻辑:
function Button(text) {
EventEmitter.call(this); // 继承实例属性(如 _events)
this.text = text;
}
// 关键:建立原型链继承
Object.setPrototypeOf(Button.prototype, EventEmitter.prototype);
// 可选:修正 constructor 指向
Button.prototype.constructor = Button;
// 使用示例
const btn = new Button('提交');
btn.on('click', () => console.log('按钮被点击了'));
btn.emit('click'); // 输出:按钮被点击了
更现代的写法:用 class + extends(底层仍是原型链)
ES6 class 语法更清晰,本质仍是基于原型链的继承:
class EventEmitter {
constructor() {
this._events = Object.create(null);
}
on(type, listener) {
if (!this._events[type]) this._events[type] = [];
this._events[type].push(listener);
return this;
}
emit(type, ...args) {
const listeners = this._events[type];
if (Array.isArray(listeners)) {
listeners.forEach(fn => fn.call(this, ...args));
}
return this;
}
off(type, listener) {
const listeners = this._events[type];
if (Array.isArray(listeners)) {
const i = listeners.indexOf(listener);
if (i > -1) listeners.splice(i, 1);
}
return this;
}
}
class InputField extends EventEmitter {
constructor(name) {
super(); // 调用父类 constructor
this.name = name;
}
}
const input = new InputField('username');
input.on('change', value => console.log(`输入值:${value}`));
input.emit('change', 'admin');
注意事项与实用建议
-
避免污染原生原型:不要给
Object.prototype或Function.prototype添加方法,只在自定义类上扩展 -
监听器执行上下文:
emit中使用fn.call(this, ...args)确保监听器里的this指向当前实例 -
内存管理:长期运行的对象记得在销毁前调用
off清理监听器,防止内存泄漏 -
事件命名约定:建议统一用小写字母加中划线(如
value-change),避免大小写混用导致匹配失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










