Actionscript 3 ActionScript 3.0为事件处理程序使用闭包

Actionscript 3 ActionScript 3.0为事件处理程序使用闭包,actionscript-3,events,closures,Actionscript 3,Events,Closures,我试着这样做: root.addEventListener("click", function () { navigateToURL(ClickURLRequest,"_self"); }); 它确实添加了事件侦听器。我喜欢使用闭包,因为它们在这种情况下工作得很好 但是,删除事件侦听器需要引用原始函数,并且由于我使用了匿名闭包,因此无法工作,我尝试了以下操作: root.removeEventListener("click", fun

我试着这样做:

root.addEventListener("click", 
   function () 
   { 
      navigateToURL(ClickURLRequest,"_self"); 
   });
它确实添加了事件侦听器。我喜欢使用闭包,因为它们在这种情况下工作得很好

但是,删除事件侦听器需要引用原始函数,并且由于我使用了匿名闭包,因此无法工作,我尝试了以下操作:

   root.removeEventListener("click", 
       function () 
       { 
          navigateToURL(ClickURLRequest,"_self"); 
       });
以及:

   root.removeEventListener("click", function () {} );
我发现它唯一可行的方法是放弃匿名闭包,将事件侦听器指向一个预先存在的函数:

 function OnClick (e:Event)
 {
     navigateToURL(ClickURLRequest,"_self");
 }

 root.addEventListener("click", OnClick);
 root.removeEventListener("click", OnClick);

有人知道如何在保留删除匿名闭包的能力的同时为事件处理程序使用匿名闭包吗?

您可以将function()关键字视为构造函数,每次都创建一个新对象(闭包)。因此,如果创建闭包只是作为参数,而不在任何地方保留引用,那么就无法在其他地方获得“相同”的闭包


显而易见的解决方案是你不喜欢的,在使用函数之前先定义它。当然,它仍然可以是一个完整的闭包,而不仅仅是一个“类似静态”的函数。只需在您想要的上下文中定义它,并将其分配给局部变量。

我不确定这是否可行,但值得一试:

root.removeEventListener("click", arguments.callee );

有关它的更多信息,请参见

这里有一种删除我在生产项目中使用的事件侦听器的通用方法


addEventListener
(
    Event.ACTIVATE, 
    function(event:Event):void
    {
        (event.target as EventDispatcher).removeEventListener(event.type, arguments.callee)             
    }
)

它与使用定义的函数没有太大区别,但这可能会满足您的需要。请记住,函数是ActionScript中的一级对象,您可以将它们作为变量存储和传递

protected function addListener() { m_handler = function(in_event:Event) { removeEventListener(MouseEvent.CLICK, m_handler); m_handler=null} addEventListener(MouseEvent.CLICK, m_handler) } protected var m_handler:Function 受保护的函数addListener() { m_handler=function(in_event:event){removeEventListener(MouseEvent.CLICK,m_handler);m_handler=null} addEventListener(MouseEvent.CLICK,m_处理程序) } 受保护的var m_处理程序:函数
在Adobe网站上的一周教程中,我在Flex中看到了一个关于代码的旁注。在这里,他们说您应该始终使用事件类型的常量,而不是字符串。这样你就可以得到打字保护。如果您在事件类型字符串(比如说“clse”)中输入错误,您的事件处理程序将被注册,但当然不会被调用。相反,请使用Event.CLOSE,这样编译器将捕捉到输入错误。

我不知道您实际在做什么,但在这个特定示例中,您可能有一个_clickEnabled全局变量

然后在事件处理程序中只需选中_clickEnabled,如果为false,则立即返回

然后,您可以启用和禁用整个事件,而无需分离和重新连接它

我发现自己经常这样做,所以我尝试了这个。看起来很好用

我有时会这样说:

var closure:Function = null;
root.addEventListener("click", 
   closure = function () 
   { 
      navigateToURL(ClickURLRequest,"_self"); 
   });

root.removeEventListener("click", closure);

正如已经建议的那样,您可以从闭包本身的侦听器链中删除闭包。这是通过使用参数来完成的。被调用方:

myDispatcher.addEventListener("click", function(event:Event):void
{
    IEventDispatcher(event.target).removeEventListener(event.type, arguments.callee);

    // Whatever else needs doing goes here
});
这将有效地将闭包转变为事件的一次性侦听器,只要在事件触发后将其自身分离即可。虽然在语法上冗长,但对于那些真正只触发一次(或您只关心一次)的事件(例如Flex中的“creationComplete”)来说,这是一种非常有用的技术。我在下载数据时总是使用这个,因为我认为内联回调代码更容易理解。这就像是隐藏了不同步性:

myLoader.addEventListener("complete", function(event:Event):void
{
    /* Even though the load is asynchronous, having the callback code inline
     * like this instead of scattered around makes it easier to understand,
     * in my opinion. */
});
但是,如果您想多次收听该事件,由于明显的原因,这将不会非常有效。在这种情况下,您需要将对闭包的引用存储在某个位置。方法是ActionScript中的对象,可以传递。因此,我们可以将代码更改为如下所示:

var closure:Function;

myDispatcher.addEventListener("click", function(event:Event):void
{
    closure = arguments.callee;

    // Whatever else needs doing goes here
});
当需要删除事件侦听器时,请使用“closure”引用,如下所示:

myDispatcher.removeEventListener("click", closure);
显然,这是一个抽象的示例,但使用这样的闭包可能非常有用。不过,它们也有缺点,例如效率不如命名方法。另一个缺点是,如果需要,实际上必须存储对闭包的引用。然后必须注意保持该引用的完整性,就像对待任何其他变量一样


因此,虽然不同的语法可能有其用途,但它并不总是最好的解决方案。这是苹果和桔子的事。

是的,我同意哈维尔的看法。如果不保留引用,则无法删除该函数。我支持此操作。还请注意,您在示例中输入了一个错误:“argumnts”哎呀,我的错,它现在已经修复了;)明亮的我自己从来没有想到过这个。我一直在用这个。它非常有用,虽然在我看来它不必要的冗长,这当然是ActionScript语法的错误,但它的技术仍然很好。我使用了一个全局函数来清理它。请看我对这个问题的回答:为什么不使用weakReference?
myDispatcher.removeEventListener("click", closure);