我正在尝试实现 removeEventListener(off) 方法。我已将代码放在下面。 off
方法删除由 on
添加的事件。
但是,当使用once
时,off
方法不会删除事件。我该如何解决这个问题?
class Emitter {
constructor() {
this.events = {};
}
on(eventName, callBack) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callBack);
return this.events[eventName].length;
}
off(eventName, callBack) {
// First get the correct event
let list = this.events[eventName];
// Check that the event exists and it has the callback registered
if (list) {
// if no callback function provided, then all functions are unsubscribed
// event has no callbacks left, delete the event
if (!callBack) {
delete this.events[eventName];
} else {
// if it is registered then unregister it!
while(list.indexOf(callBack) !== -1) {
// If the callback is in the array then remove it
let index = list.indexOf(callBack);
list.splice(index, 1);
}
// if the event has no callbacks left, delete the event
if (list.length === 0) {
delete this.events[eventName];
}
}
}
return (this.events[eventName] || []).length;
}
once(event, fn) {
//If the event name is not a string data type throw error
if (typeof event !== 'string') throw Error();
// If the callback is not a function data type throw error
if (typeof fn !== 'function') throw Error();
function g () {
this.off(event, g);
fn.apply(this, arguments);
}
g.fn = fn;
this.on(event, g);
return this.events[event].length;
};
}
let e = new Emitter();
console.log(e.events);
function test(){};
e.on('test', test);
console.log(e.events);
e.off('test', test);
console.log(e.events);
console.log('==========');
console.log(e.events);
function test(){};
e.once('test', test);
console.log(e.events);
e.off('test', test);
console.log(e.events);
最佳答案
为什么e.off('test', test);
的原因不删除处理程序是因为 test
不是您要添加到 this.events[eventName]
的处理程序与 .once
.您正在创建一个新函数 g
, that 是存储在 this.events[eventName]
中的那个. .off
然而,只会查看您作为参数传递的函数是否包含在数组中,事实并非如此。
How can I fix this?
有多种方法可以解决这个问题。通常,订阅方法实际上会返回一个 token 或可用于取消订阅的其他一些值。这样做的好处是调用者不必保留对处理程序的引用。示例:
once(event, fn) {
//If the event name is not a string data type throw error
if (typeof event !== 'string') throw Error();
// If the callback is not a function data type throw error
if (typeof fn !== 'function') throw Error();
function g () {
this.off(event, g);
fn.apply(this, arguments);
}
this.on(event, g);
return {
unsubscribe: () => this.off(event, g);
};
}
// which can later be called as
const subscription = e.once('test', test);
subscription.unsubscribe();
但是,由于您已经通过 g.fn = fn;
跟踪原始函数, 你可以调整你的 .off
方法来检查任何已注册的事件处理程序是否具有与传入值匹配的属性。像这样的东西:
// if it is registered then unregister it!
this.events[eventName] = this.events[eventName].filter(
handler => handler !== callBack && handler.fn !== callBack;
);
关于javascript - 删除事件监听器实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50281778/