javascript - 删除事件监听器实现

标签 javascript

我正在尝试实现 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/

相关文章:

javascript - 用键值存储数组

javascript - 在动态生成的 DOM 上取消初始化/重新初始化 tinyMCE

javascript - 如何检查客户端 JavaScript 中的端口可用性?

javascript - 上传文件而不重新加载整页

javascript - 在功能模块的组件中使用应用程序模块的组件

重复分配的 JavaScript 开销

javascript - 子菜单需要是浏览器窗口的全宽

javascript - setinterval 不在整个应用程序中更新/刷新 - Node.js

javascript - 无法更改 jquery 自动完成中的文本值

javascript - 如何将整个页面保存为一个文件以便离线工作(包括外部 javascript)?