在循环中创建一个函数(指针?)

问题描述 投票:0回答:3

我试图创建一个简单的循环,创建50个按钮,将它们添加到屏幕,然后当按下按钮时,它会追踪该数字。我可以通过做我认为hacky的东西(比如使用按钮X / Y位置来确定它的值)让它工作,但我宁愿只能在函数中保存一个值。

代码本身是:

for (var a:int = 0; a < 5; a++) {
    for (var b:int = 0; b < 10; b++) {
        var n = (a * 10) + b + 1;
        var btt:SimpleButton = new BasicGameButton();
        btt.x = 20 + b * 50;
        btt.y = 50 + a * 80;
        addChild(btt);
        btt.addEventListener(MouseEvent.CLICK, function f() { trace(n); } );
    }
}

此时,只要按下按钮,它就会输出“50”。对于该函数,有没有一种方法可以在创建函数时“冻结”n的值? (BasicGameButton只是一个方形按钮,在flash库中创建)

非常感谢。

flash actionscript-3 actionscript flash-cs4
3个回答
0
投票

这是一个AS3缺陷,来自废弃的ECMA脚本草案AS3基于... n的范围是它声明的最内层函数体(因此好像它是在循环之前声明的),虽然在最里面的循环中声明你的代码的主体。

你可以做到以下几点:

var makeFunction:Function = function (n:int):Function {//this can of course also be a method
    return function (event:MouseEvent):void {
         trace(n);
    }
}

//in the loop body, use it like this:
btt.addEventListener(MouseEvent.CLICK, makeFunction(n));

作为旁注:Haxe没有这个缺陷。


0
投票

我看到答案已被选中,但我不同意解决方案,尽管它确实有效。我不认为这是AS3的一个缺陷,因为这种情况与Javascript相同,也基于ECMAScript。在任何情况下,只需为BasicGameButton创建一个包含n值的属性,就可以完全避免这个问题。此外,不是为每个按钮添加一个侦听器,只需在按钮容器上创建一个侦听器,该侦听器侦听鼠标单击(鼠标单击“气泡”直到父显示对象)并使用事件目标获取单击的按钮。

/* inside the loop */
btt.n = n;

/* parent listener you only have to create once */
buttonContainer.addEventListener(MouseEvent.CLICK, onClick);

function onClick(e:Event):void {
    trace(BasicGameButton(e.target).n);
}

0
投票

我同意wpjmurray这不是一个缺陷;相反,它是范围在EcmaScript中如何工作的结果。

您的单击处理程序带有对变量的隐式引用(n)。调用该函数(通过单击触发)时,该变量的值已更改。当你以这种方式思考时,这是完全有道理的。

解决方案是将值存储在每次迭代中,并以某种方式将其与您的按钮相关联。有三种好方法可以做到这一点:

  1. 创建一个新的闭包,它本身具有对另一个变量的隐式引用,该变量的值设置一次然后单独保留。 back2dos的解决方案是一种方法:makeFunction创建一个新的方法闭包,它隐含引用一个新的变量(makeFunctionn参数),它不会改变。
  2. 将值存储为对象的属性。 (这是wpjmurray提出的,但你无法做到。)
  3. 将值存储在地图中并查找。当您提到将X / Y坐标映射到索引时,您暗示了这一点。但是,ActionScript 3提供了更多......优雅(:解决方案:Dictionary class!只需将对象本身映射到索引,然后在处理程序中查找它。

这是一个例子:

var dict:Dictionary = new Dictionary(true);
for (var a:int = 0; a < 5; a++) {
    for (var b:int = 0; b < 10; b++) {
        var n = (a * 10) + b + 1;
        var btt:SimpleButton = new BasicGameButton();
        btt.x = 20 + b * 50;
        btt.y = 50 + a * 80;
        addChild(btt);
        dict[btt] = n;
        btt.addEventListener(MouseEvent.CLICK, function f(event:MouseEvent) { trace(dict[event.currentTarget]); } );
    }
}

由于范围在EcmaScript中的工作方式,您创建的每个单击处理程序都带有对字典的隐式引用,您可以使用它来查找索引。现在,索引直接映射到按钮,而无需添加属性或创建新函数。

© www.soinside.com 2019 - 2024. All rights reserved.