面试题答案
一键面试// 创建一个事件监听系统的类
class EventEmitter {
constructor() {
// 用于存储事件和对应的监听器
this.events = {};
}
// 添加事件监听器的方法
on(eventName, callback, context) {
// 如果该事件名对应的监听器数组不存在,则创建一个新的数组
if (!this.events[eventName]) {
this.events[eventName] = [];
}
// 将监听器(包括回调函数和作用域)添加到对应的事件数组中
this.events[eventName].push({ callback, context });
}
// 移除事件监听器的方法
off(eventName, callback) {
// 如果该事件名对应的监听器数组存在
if (this.events[eventName]) {
// 使用高阶函数filter过滤掉要移除的监听器
this.events[eventName] = this.events[eventName].filter(listener => listener.callback!== callback);
}
}
// 触发事件的方法
emit(eventName, ...args) {
// 如果该事件名对应的监听器数组存在
if (this.events[eventName]) {
// 遍历并执行所有该事件的监听器
this.events[eventName].forEach(listener => {
const { callback, context } = listener;
// 使用call方法来确保回调函数在指定的作用域内执行
callback.call(context, ...args);
});
}
}
}
// 示例使用
// 创建一个事件发射器实例
const emitter = new EventEmitter();
// 添加一个事件监听器
emitter.on('testEvent', function (data) {
console.log(`在事件作用域 ${this.name} 中接收到数据:`, data);
}, { name: '示例作用域' });
// 触发事件
emitter.emit('testEvent', 'Hello, Event System!');
// 移除事件监听器
emitter.off('testEvent', function (data) {
console.log(`在事件作用域 ${this.name} 中接收到数据:`, data);
}, { name: '示例作用域' });
// 再次触发事件,监听器已移除,不会有输出
emitter.emit('testEvent', 'Hello, Event System!');
代码说明
-
EventEmitter 类:
- constructor:初始化一个空的
events
对象,用于存储事件和对应的监听器数组。 - on 方法:
- 接受
eventName
(事件名)、callback
(回调函数)和context
(事件作用域)作为参数。 - 检查
events
对象中是否存在指定的eventName
,如果不存在则创建一个空数组。 - 将监听器(包含
callback
和context
)添加到对应的事件数组中。
- 接受
- off 方法:
- 接受
eventName
和callback
作为参数。 - 检查
events
对象中是否存在指定的eventName
,如果存在则使用filter
方法过滤掉要移除的监听器。
- 接受
- emit 方法:
- 接受
eventName
和可变数量的参数...args
。 - 检查
events
对象中是否存在指定的eventName
,如果存在则遍历并使用call
方法在指定的context
作用域内执行所有监听器,并传递参数。
- 接受
- constructor:初始化一个空的
-
示例使用:
- 创建一个
EventEmitter
实例emitter
。 - 使用
on
方法添加一个testEvent
事件的监听器,指定了事件作用域。 - 使用
emit
方法触发testEvent
事件,并传递数据。 - 使用
off
方法移除testEvent
事件的监听器。 - 再次触发
testEvent
事件,由于监听器已移除,不会有任何输出。
- 创建一个
这样就实现了一个基本的通用事件监听系统,涵盖了添加事件监听器、移除事件监听器以及触发事件的功能,并考虑了事件作用域。如果要考虑事件委托,可以在 emit
方法中添加逻辑,例如在触发父级事件时,判断是否需要同时触发子级事件等,这里暂未详细展开事件委托相关代码,如需进一步实现可根据具体需求修改。