从数组/对象/集合中删除匿名 JavaScript 函数

Posted

技术标签:

【中文标题】从数组/对象/集合中删除匿名 JavaScript 函数【英文标题】:Remove anonymous JavaScript function from array/object/Set 【发布时间】: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

【问题讨论】:

【参考方案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)

【讨论】:

以上是关于从数组/对象/集合中删除匿名 JavaScript 函数的主要内容,如果未能解决你的问题,请参考以下文章

Mongodb,使用javascript从一组对象中删除一个对象

使用JavaScript从数组中删除对象

从对象数组中删除元素javascript

jQuery / Javascript从对象数组中删除一个对象[重复]

如何从 JavaScript 关联数组中删除对象?

javascript 从javascript中的对象数组中删除重复项