在循环中创建一个函数(指针?)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在循环中创建一个函数(指针?)相关的知识,希望对你有一定的参考价值。
我试图创建一个简单的循环,创建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库中创建)
非常感谢。
这是一个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没有这个缺陷。
我看到答案已被选中,但我不同意解决方案,尽管它确实有效。我不认为这是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);
}
我同意wpjmurray这不是一个缺陷;相反,它是范围在EcmaScript中如何工作的结果。
您的单击处理程序带有对变量的隐式引用(n
)。调用该函数(通过单击触发)时,该变量的值已更改。当你以这种方式思考时,这是完全有道理的。
解决方案是将值存储在每次迭代中,并以某种方式将其与您的按钮相关联。有三种好方法可以做到这一点:
- 创建一个新的闭包,它本身具有对另一个变量的隐式引用,该变量的值设置一次然后单独保留。 back2dos的解决方案是一种方法:
makeFunction
创建一个新的方法闭包,它隐含引用一个新的变量(makeFunction
的n
参数),它不会改变。 - 将值存储为对象的属性。 (这是wpjmurray提出的,但你无法做到。)
- 将值存储在地图中并查找。当您提到将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中的工作方式,您创建的每个单击处理程序都带有对字典的隐式引用,您可以使用它来查找索引。现在,索引直接映射到按钮,而无需添加属性或创建新函数。
以上是关于在循环中创建一个函数(指针?)的主要内容,如果未能解决你的问题,请参考以下文章