【问题标题】:Remove anonymous JavaScript function from array/object/Set从数组/对象/集合中删除匿名 JavaScript 函数
【发布时间】:2017-03-23 00:04:54
【问题描述】:

Node的emitter.removeListener如何在ES2015中实现?向数组添加回调很简单:

let callbacks = [];
function registerCallback(handler) {
    callbacks.push(handler);
});

那个特定的函数以后如何在没有 registerCallback 返回 some identifier for the function 的情况下被删除?换句话说,unregisterCallback(handler) 应该不需要任何其他参数,并且应该删除该处理程序。 unregisterCallback 将如何检查之前是否添加了匿名函数?

运行handler.toString()(可能还有一个哈希函数)是为函数创建标识符的可靠解决方案吗?或者unregisterCallback 应该如何遍历callbacks 以删除该特定元素? (或者在 Set 中的对象或函数中找到适当的键。)

mySet.add(function foo() { return 'a'})
mySet.has(function foo() { return 'a'})  // false

【问题讨论】:

    标签: javascript ecmascript-6 symbols


    【解决方案1】:

    通常的解决方案是将函数本身作为参数传递给unregisterCallback 函数。例如,这就是在 jQuery 中所做的。

    所以unregisterCallback 函数只需要使用indexOf 来查找回调的索引:

    function unregisterCallback(handler) {
        var index = callbacks.indexOf(handler);
        if (~index) callbacks.splice(index, 1);
    }
    

    当然这意味着用户代码必须保留该函数,它不能是调用registerCallback时定义的函数。

    这不起作用:

    registerCallback(function foo() { return 'a'});
    // later...
    unregisterCallback(function foo() { return 'a'}); // this is a different function
    

    这行得通:

    function foo(){
        return 'a'
    }
    registerCallback(foo);
    // later...
    unregisterCallback(foo); // it's the same function
    

    您还可以提供按名称删除的功能:

    // pass either the function or its name
    function unregisterCallback(handler) {
      var index = -1;
      if (typeof handler==="string") {
          for (var i=0; i<callbacks.length; i++) {
            if (callbacks[i].name===handler) {
              index = i;
              break;
            }
          }
      } else {
          index = callbacks.indexOf(handler);
      }
      if (~index) callbacks.splice(index, 1);
    }
    registerCallback(function foo() { return 'a'});
    unregisterCallback("foo");
    

    但是名称唯一性的责任在于用户代码领域,这可能好也可能不好,具体取决于您的应用程序。

    【讨论】:

    • 谢谢。使用函数本身作为键也适用于 Set。
    • 有趣的是,setTimeout()setInterval() 返回一个标识符,而不是 clearTimeout()clearInterval() 采用相同的功能。
    • @DanDascalescu 是的,这很有趣。这可能是因为这些函数是在 JavaScript 的 "functions as first-class citizen" 本质在文化上显而易见之前设计的。 JavaScript 最初的设计速度非常快,许多最初的设计都可以追溯到在该领域很差的 Java。这也可能是实现泄漏的情况。
    • @DanDascalescu 有人指出,在setTimeoutsetInterval 中使用函数本身会使在多个计时器中使用相同的函数变得更加困难。
    【解决方案2】:

    您可以选择design,其中事件发射器返回一个可更新内部状态的可调用对象:

    const dispose = sleep.on('sheep', ::sleep.tick)
    sleep.once('baanough', dispose)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      • 1970-01-01
      • 2016-05-19
      • 2019-07-22
      • 2019-04-24
      • 2020-12-07
      • 2016-08-12
      相关资源
      最近更新 更多