在事件处理程序中删除自身的事件处理程序

7
简而言之:我想将.bind的结果绑定为它自己调用时的参数。
var bound = foo.bind(this,bound);

因为我不确定如何解决我的问题。

问题:

我有一个依赖于其他项目数组的项目。 当其中一个项目被移除时,我希望移除依赖项目,并移除所有放置在依赖项上的监听器。

我正在努力删除其他依赖项的事件处理程序。我尝试使用bind,但由于处理程序函数是删除侦听器的函数,因此我发现我必须将bind()调用的结果绑定到它自己的调用作为参数中。这当然是行不通的。

下面的绑定调用将未绑定版本的“handler”绑定为参数,因此removeEventListener无法正常工作,因为它是函数的不同副本。

问题是:我可以使用bind来做到这一点吗?或者我该如何解决这个问题?

我使用eventemitter3,但对于任何事件库都应该是相同的。

setHandlers(dependentItem,dependencies)
{
    var handler = this.onDependencyRemoved;
    handler = handler.bind(this,dependentItem,dependencies,handler);//bind itself as third argument
    dependencies.forEach(dependency => {
        dependency.addEventListener("removed",handler);
    });
}
onDependencyRemoved(dependentItem,dependencies,handler)
{
     dependentItem.remove();
     dependencies.forEach(dependency => {
          dependency.removeEventListener("removed",handler);
     });
}

编辑:

在nodejs中运行的完整工作示例:

const EventEmitter = require('events');
//const EventEmitter = require('eventemitter3');

class MyEmitter extends EventEmitter {
    remove() {
        console.log("I'm being removed, this should happen only once");
    }
}
var dependent = new MyEmitter();
var dependencies = [new MyEmitter(),new MyEmitter()];

var handler = (e) => removeHandler(dependencies,dependent,handler);

dependencies.forEach(dependency => dependency.once('removed',handler));

var removeHandler = function(dependencies,dependent,handler) {
    //remove the dependent object because one of the dependencies was removed
    dependent.remove();
    //remove the listeners from all of the dependencies
    dependencies.forEach(dependency => {
        console.log('before removing: '+dependency.listeners('removed').length);
        dependency.removeListener('removed',handler);
        console.log('after removing: '+dependency.listeners('removed').length);
    });
}

//should remove the dependent object
dependencies[0].emit("removed");
//should not do anything anymore since the listeners are removed
dependencies[1].emit("removed");

使用事件委托在父元素上添加一个处理程序。 - Andreas
@Andreas 我在使用node.js。这些项目是模型/ES6类实例,而不是DOM项目。 - Flion
2个回答

7

你无法使用bind实现这一点,但是通过使用闭包,你可以相对容易地实现它-要么直接在要绑定的函数中使用闭包,要么在自己的帮助程序函数中类似于bind。这很简单

const handler = (e) => this.onDependencyRemoved(dependentItem, dependencies, handler, e);

我不确定为什么这两个函数是任何东西的方法;它们看起来相当静态。也许将它们作为dependentItem的方法可能有意义,在这种情况下,参数甚至整个handler都不需要存储在闭包变量中,而可以成为实例属性在构造函数中初始化。


使用闭包后仍然无法正常工作。当我移除事件监听器时,一旦注册的处理程序与onDependencyRemoved使用的处理程序不匹配(===)。我已经编辑了带有闭包设置的问题。 - Flion
@Flion,我无法重现你的问题,你的代码应该可以工作。我相信你要么没有展示完整的实际代码,要么问题出在其他地方。你能否制作一个 [mcve]?我也很好奇你如何检查 === "against the handler function once saved with addEventListener",因为 addEventListener 不会使其存储可用。 - Bergi
1
是的,我刚刚创建了一个最小完整示例,并且在使用node.js本地EventEmitter和eventEmitter3库时都可以正常工作。我意识到并不是每次调用removeEventListener时都会删除某些内容,因为发出“removed”事件的项目已经自己删除了它,因为我使用了once。感谢您的帮助!我明天会给予奖励。这对我来说是一个重要问题,而我从未知道一个简单的闭包可以像您展示的那样在其自己的函数中重用值。 - Flion

6

有其他人提到的更好的方法来解决你的问题。然而,代码中存在一个更基本的问题:

var bound = foo.bind(this,bound);

你的代码中,bound 值在执行时是 undefined。这相当于仅调用 foo.bind(this),这可能不是你想要的。

我知道这一点,我只是写下来试图解释我想做什么。 - Flion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接