事件发射器
问题
设计一个 EventEmitter 类。这个接口与 Node.js 或 DOM 的 Event Target 接口相似,但有一些差异。EventEmitter 应该允许订阅事件和触发事件。
你的 EventEmitter 类应该有以下两个方法:
subscribe - 这个方法接收两个参数:一个作为字符串的事件名和一个回调函数。当事件被触发时,这个回调函数将被调用。 一个事件应该能够有多个监听器。当触发带有多个回调函数的事件时,应按照订阅的顺序依次调用每个回调函数。应返回一个结果数组。你可以假设传递给 subscribe 的回调函数都不是引用相同的。 subscribe 方法还应返回一个对象,其中包含一个 unsubscribe 方法,使用户可以取消订阅。当调用 unsubscribe 方法时,回调函数应该从订阅列表中删除,并返回 undefined。 emit - 这个方法接收两个参数:一个作为字符串的事件名和一个可选的参数数组,这些参数将传递给回调函数。如果没有订阅给定事件的回调函数,则返回一个空数组。否则,按照它们被订阅的顺序返回所有回调函数调用的结果数组。
示例 1:
输入: actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"], values = [[], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent"]] 输出:[[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]] 解释: const emitter = new EventEmitter(); emitter.emit("firstEvent"); // [], 还没有订阅任何回调函数 emitter.subscribe("firstEvent", function cb1() { return 5; }); emitter.subscribe("firstEvent", function cb2() { return 6; }); emitter.emit("firstEvent"); // [5, 6], 返回 cb1 和 cb2 的输出 示例 2:
输入: actions = ["EventEmitter", "subscribe", "emit", "emit"], values = [[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["firstEvent", [3,4,6]]] 输出:[[],["subscribed"],["emitted",["1,2,3"]],["emitted",["3,4,6"]]] 解释:注意 emit 方法应该能够接受一个可选的参数数组。
const emitter = new EventEmitter(); emitter.subscribe("firstEvent, function cb1(...args) { return args.join(','); }); emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"] emitter.emit("firstEvent", [3, 4, 6]); // ["3,4,6"] 示例 3:
输入: actions = ["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"], values = [[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]] 输出:[[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[]]] 解释: const emitter = new EventEmitter(); const sub = emitter.subscribe("firstEvent", (...args) => args.join(',')); emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"] sub.unsubscribe(); // undefined emitter.emit("firstEvent", [4, 5, 6]); // [], 没有订阅者 示例 4:
输入: actions = ["EventEmitter", "subscribe", "subscribe", "unsubscribe", "emit"], values = [[], ["firstEvent", "x => x + 1"], ["firstEvent", "x => x + 2"], [0], ["firstEvent", [5]]] 输出:[[],["subscribed"],["subscribed"],["unsubscribed",0],["emitted",[7]]] 解释: const emitter = new EventEmitter(); const sub1 = emitter.subscribe("firstEvent", x => x + 1); const sub2 = emitter.subscribe("firstEvent", x => x + 2); sub1.unsubscribe(); // undefined emitter.emit("firstEvent", [5]); // [7]
答案
没看懂
class EventEmitter {
constructor(){
this.events={};
}
/**
* @param {string} eventName
* @param {Function} callback
* @return {Object}
*/
subscribe(eventName, callback) {
this.events[eventName]=this.events[eventName]??[];
this.events[eventName].push(callback);
return {
unsubscribe: () => {
this.events[eventName] = this.events[eventName].filter(f=>f!==callback);
if(this.events[eventName].length===0){
delete this.events[eventName];
}
}
};
}
/**
* @param {string} eventName
* @param {Array} args
* @return {Array}
*/
emit(eventName, args = []) {
if(!(eventName in this.events)) return [];
return this.events[eventName].map(f=>f(...args));
}
}
/**
* const emitter = new EventEmitter();
*
* // Subscribe to the onClick event with onClickCallback
* function onClickCallback() { return 99 }
* const sub = emitter.subscribe('onClick', onClickCallback);
*
* emitter.emit('onClick'); // [99]
* sub.unsubscribe(); // undefined
* emitter.emit('onClick'); // []
*/
扩展
a ?? b
如果 a 是 null 或 undefined,返回 b
否则返回 a
与 || 不同的是,?? 不会把 0、false、'' 这些“假值”当作空值。
- 检查对象是否有该属性
let obj = { a: undefined };
'a' in obj; // true(即使值是 undefined)
'b' in obj; // false
in 检查的是属性名是否存在,而不是值是否为真。