Javascript, для цикла не будет работать - PullRequest
2 голосов
/ 15 июня 2011
var a=0;
setTimeout (function () { animatedDraw(context, 20+32*level[0],20*0, textArray[0]); }, timeArray[0]);
setTimeout (function () { animatedDraw(context, 20+32*level[1],20*1, textArray[1]); }, timeArray[1]);
setTimeout (function () { animatedDraw(context, 20+32*level[2],20*2, textArray[2]); }, timeArray[2]);
setTimeout (function () { animatedDraw(context, 20+32*level[3],20*3, textArray[3]); }, timeArray[3]);
setTimeout (function () { animatedDraw(context, 20+32*level[4],20*4, textArray[4]); }, timeArray[4]);
setTimeout (function () { animatedDraw(context, 20+32*level[5],20*5, textArray[5]); }, timeArray[5]);

for (a=0; a<6; a++)
    setTimeout (function () { animatedDraw(context, 20+32*level[a],20*0, textArray[a]); }, timeArray[a]);

Первая часть моего кода - это часть, которая работает.Вторая часть не появляется.Я рисую на холсте (HTML 5), но когда я выдал шесть окон с предупреждениями, показывалось окно с предупреждением.Я делаю что-то очень глупое неправильно?

Заранее спасибо

Ответы [ 3 ]

12 голосов
/ 15 июня 2011

Причина в том, что функции, которые вы вводите в setTimeout, являются замыканиями, а замыкания имеют устойчивую ссылку на переменные, которые они закрывают, а не копию их значения по состоянию на момент создания закрытия. Следовательно, все эти функции будут пытаться использовать одно и то же значение a, значение, которое оно имеет после , когда цикл завершен (например, 6), и поэтому они потерпят неудачу.

Ответ заключается в том, чтобы функции закрывали некоторые другие данные, которые не будут меняться. Обычный способ сделать это состоит в том, чтобы иметь фабричную функцию, которая создает и возвращает фактические функции, которые вы хотите, закрывая их по аргументу, который вы вводите в фабричную функцию (которая не изменится), а не по переменной цикла. E.g.:

for (a=0; a<6; a++) {
    setTimeout(makeTimerFunction(a), timeArray[a]);
}

function makeTimerFunction(index) {
    return function () {
        animatedDraw(context, 20+32*level[index],20*0, textArray[index]);
    };
}

Как вы можете видеть, теперь функции, создаваемые makeTimerFunction, закрываются по index, а не a (а также по context, level и textArray; вы пропустите эти в том числе, если они изменятся).

Подробнее о замыканиях: Закрытия не сложны

2 голосов
/ 15 июня 2011

Это очень распространенная проблема закрытия Javascript.

Ваша переменная a в цикле продолжает изменяться во время цикла, поэтому значение, используемое в обратных вызовах, будет значением last , которое оно имело, а не значением, которое оно получало каждый раз в течение цикла. цикл.

Самый простой способ исправить это:

function timer_setup(a) {
    setTimeout(function () {
        animatedDraw(context, 20+32*level[a],20*0, textArray[a]);
    }, timeArray[a]);
};

for (a=0; a<6; a++) {
    timer_setup(a);
}
0 голосов
/ 15 июня 2011

Попробуйте это ...

for (a=0; a<6; a++)
{
    (function(index)
    {
        setTimeout (function () { animatedDraw(context, 20+32*level[index],20*0, textArray[index]); }, timeArray[index]);
    })(a)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...