从 array/object/Set 中删除匿名 JavaScript 函数

Remove anonymous JavaScript function from array/object/Set

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

通常的解决方案是将函数本身作为参数传递给 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");

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

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

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