Actionscript 3 AS3关闭混乱

Actionscript 3 AS3关闭混乱,actionscript-3,closures,Actionscript 3,Closures,我有一个小圈圈 var a:Array = [{name:Test1},{name:Test2},{name:Test3},{name:Test4}] var b:GenericButton; //A pretty basic button component for(var i:int = 0; i < a.length; i++){ b = new GenericButton(a[i].name, function():void { trace(i) }); this.add

我有一个小圈圈

var a:Array = [{name:Test1},{name:Test2},{name:Test3},{name:Test4}]
var b:GenericButton; //A pretty basic button component

for(var i:int = 0; i < a.length; i++){
  b = new GenericButton(a[i].name, function():void { trace(i) });
  this.addChild(b);
}
var a:Array=[{name:Test1},{name:Test2},{name:Test3},{name:Test4}]
VarB:通用按钮//一个非常基本的按钮组件
对于(变量i:int=0;i
当按下按钮时,将执行提供给GenericButton的功能

我遇到的问题是,无论按什么按钮,值4(数组的长度)总是输出


我如何确保在按下第一个按钮时跟踪0,在按下第二个按钮时跟踪1,等等?

好吧,您可以简单地执行以下操作:

var f:* = function():void { trace(arguments.callee.index) };
f.index = i;
b = new GenericButton(a[i].name, f);
更好的是:

function createDelegate(obj:Object, func:Function):Function
{
    var f:* = function ():* {
        var thisArg:* = arguments.callee.thisArg;
        var func:* = arguments.callee.func;

        return func.apply(thisArg, arguments);
    };

    f.thisArg = obj;
    f.func = func;

    return f;
}


在某些(大多数?)情况下,如果您创建一个单独的类并将
i
传递到构造函数中会更好。

这是使用闭包时最基本的错误。您可能认为创建GenericButton时设置了
i
。但闭包只需获得变量
i
的直接链接,并在调用匿名函数时使用此链接。此时,循环结束,所有指向
i
的链接都指向同一个值为4的整数。
要解决这个问题,只需以某种方式传递
i
的值——例如,作为GenericButton构造函数的附加参数。在这种情况下,将在每个步骤上创建一个
i
的副本,其值为0、1、2、3-就像您需要的那样

...
b = new GenericButton(a[i].name, function(i:int):void { trace(i); }, i);
...

i
存储在GenericButton中并传递到函数中-这会导致匿名函数停止使用上下文变量
i
(循环计数器),并强制它使用参数
i
生成一个返回函数的函数。这里有一个FlexUnit测试方法来演示它

    [Test]
    public function closureWin():void
    {
        var functions:Array = [];
        var mkFn:Function = function(value:int):Function
        {
            return function():int
            {
                return value;
            }
        }

        var i:int;
        for (i = 0; i < 10; i++)
        {
            functions.push(mkFn(i));
        }

        var j:int;
        for(j = 0; j < 10; j++)
        {
            assertEquals(j, functions[j]());
        }
    }   
[测试]
公共函数closureWin():void
{
var函数:数组=[];
var mkFn:Function=Function(值:int):Function
{
返回函数():int
{
返回值;
}
}
变量i:int;
对于(i=0;i<10;i++)
{
功能推送(mkFn(i));
}
var j:int;
对于(j=0;j<10;j++)
{
资产质量(j,函数[j]());
}
}   
下面是一个测试方法,演示您看到的行为:

    [Test]
    public function closureFail():void
    {
        // basically to see if this works the same way in as3 as it does in javascript
        // I expect that all the functions will return 10

        var i:int;
        var functions:Array = [];
        for (i = 0; i < 10; i++)
        {
            functions.push(function():int{return i});
        }

        var j:int;
        for each (var f:Function in functions)
        {
            assertEquals(10, f());
        }
    }
[测试]
公共函数closureFail():void
{
//基本上是为了看看它在as3中的工作方式是否与在javascript中的工作方式相同
//我预计所有函数都将返回10
变量i:int;
var函数:数组=[];
对于(i=0;i<10;i++)
{
push(function():int{return i});
}
var j:int;
对于每个(var f:函数中的函数)
{
资产质量(10,f());
}
}

为什么要使用非类型化var和非类型化return参数?它应该是
函数
无效
。我确信
参数。被调用方
在AS3中被删除了,是吗?@valentismonov函数的返回类型实际上是未知的(取决于从外部传递的
函数
f
是非类型化的,因为我们需要将
thisArg
func
粘贴到它上面。奇怪的是,如果f被键入为
函数,Flash不允许在f上设置索引,因为
函数
是动态的。@alxx
参数。被调用方
非常常见。这也是一个很好的解决方案。但是,它需要我更改GenericButton,因为上面的解决方案不需要更改。这个解决方案的解释很好。
    [Test]
    public function closureFail():void
    {
        // basically to see if this works the same way in as3 as it does in javascript
        // I expect that all the functions will return 10

        var i:int;
        var functions:Array = [];
        for (i = 0; i < 10; i++)
        {
            functions.push(function():int{return i});
        }

        var j:int;
        for each (var f:Function in functions)
        {
            assertEquals(10, f());
        }
    }