AS3 Закрытие путаницы - PullRequest
       6

AS3 Закрытие путаницы

2 голосов
/ 02 марта 2012

У меня небольшая петля

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);
}

Функция, предоставляемая GenericButton, выполняется при нажатии кнопки.

Проблема, с которой я сталкиваюсь, заключается в том, что когда неважно, какая кнопкаЯ нажимаю значение 4 (длина массива) всегда выводится.

Как мне обеспечить отслеживание 0 при нажатии первой кнопки, 1 при нажатии второй и т. Д.?

Ответы [ 3 ]

6 голосов
/ 02 марта 2012

Ну, вы можете просто сделать:

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;
}

...

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

А в некоторых (большинстве?) Случаях было бы еще лучше, если бы вы создали отдельный класс и передали i в конструктор.

1 голос
/ 23 августа 2012

Создать функцию, которая возвращает функцию. Вот тестовый метод 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]());
        }
    }   

Вот метод теста, демонстрирующий наблюдаемое вами поведение:

    [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());
        }
    }
1 голос
/ 02 марта 2012

Это самая основная ошибка при использовании замыканий.Возможно, вы думаете, что i устанавливается при создании GenericButton.Но closure просто получает прямую ссылку на переменную 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...