У меня есть этот script:
for (var i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}
Но 3 предупреждается обоим раза, а не 1, а затем 2.
Есть ли способ передать i, не записывая функцию в виде строки?
У меня есть этот script:
for (var i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}
Но 3 предупреждается обоим раза, а не 1, а затем 2.
Есть ли способ передать i, не записывая функцию в виде строки?
Вы должны организовать отдельную копию "i" для каждой функции тайм-аута.
function doSetTimeout(i) {
  setTimeout(function() { alert(i); }, 100);
}
for (var i = 1; i <= 2; ++i)
  doSetTimeout(i);
Если вы не сделаете что-то подобное (и есть другие варианты этой же идеи), то каждая из функций-обработчиков таймера будет иметь одну и ту же переменную "i". Когда цикл закончится, какое значение у "i"? Это 3! Используя посредническую функцию, создается копия значения переменной. Поскольку обработчик тайм-аута создается в контексте этой копии, у него есть свой собственный "i" для использования.
 редактировать - со временем было несколько комментариев, в которых была очевидна некоторая путаница в связи с тем фактом, что установка нескольких тайм-аутов приводит к тому, что обработчики запускаются одновременно. Важно понимать, что процесс установки таймера - вызовы setTimeout() - практически не занимают время. То есть, говоря системе "Пожалуйста, вызовите эту функцию через 1000 миллисекунд", вы вернетесь почти немедленно, так как процесс установки запроса на тайм-аут в очереди таймера очень быстрый.
Таким образом, если выполняется последовательность запросов времени ожидания, как это имеет место в коде в OP и в моем ответе, и значение задержки времени одинаково для каждого, то после того, как это количество времени истекло, все обработчики таймера будет вызываться один за другим в быстрой последовательности.
 Если вам нужно, чтобы обработчики вызывались с интервалами, вы можете либо использовать setInterval(), который вызывается точно так же, как setTimeout() но который будет срабатывать более одного раза после повторных задержек запрошенной суммы, или вместо этого вы можете установить время ожидания и умножьте значение времени на ваш счетчик итераций. То есть, чтобы изменить мой пример кода:
function doScaledTimeout(i) {
  setTimeout(function() {
    alert(i);
  }, i * 5000);
}
 (При тайм-ауте в 100 миллисекунд эффект не будет очень очевидным, поэтому я увеличил число до 5000.) Значение i умножается на значение базовой задержки, поэтому вызов 5 раз в цикле приведет к задержкам 5 секунд, 10 секунд, 15 секунд, 20 секунд и 25 секунд.
Обновить
Здесь, в 2018 году, существует более простая альтернатива. С новой возможностью объявлять переменные в областях, более узких, чем функции, оригинальный код будет работать, если так изменить:
for (let i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}
 Объявление let, в отличие от var, само по себе приведет к тому, что для каждой итерации цикла будет свой i.
Вы можете использовать функциональное выражение с немедленным вызовом (IIFE), чтобы создать замыкание вокруг setTimeout:
for (var i = 1; i <= 3; i++) {
    (function(index) {
        setTimeout(function() { alert(index); }, i * 1000);
    })(i);
}Аргумент функции setTimeout закрывает переменную цикла. Цикл заканчивается до первого таймаута и отображает текущее значение i, которое равно 3.
Поскольку переменные JavaScript имеют только область функций, решение должно передать переменную цикла функции, задающей тайм-аут. Вы можете объявить и вызвать такую функцию следующим образом:
for (var i = 1; i <= 2; i++) {
    (function (x) {
        setTimeout(function () { alert(x); }, 100);
    })(i);
}
Это потому, что !
Решение, объявляющее единую область для каждой итерации, используя выполненную самофункцию (анонимный или лучше IIFE) и имеющий копию i в нем, например:
for (var i = 1; i <= 2; i++) {
     (function(){
         var j = i;
         setTimeout(function() { console.log(j) }, 100);
     })();
}
чище было бы
for (var i = 1; i <= 2; i++) {
     (function(i){ 
         setTimeout(function() { console.log(i) }, 100);
     })(i);
}
Использование iFE (самозапускаемой функции) внутри каждой итерации создало новую область для каждой итерации, которая дала нам функцию тайм-аута, которая вызывает обратную функцию для закрытия новой области для каждой итерации, которая имела переменную с правильной переменной, итерации в нем для доступа.
Вы можете использовать дополнительные аргументы для setTimeout для передачи параметров функции обратного вызова.
for (var i = 1; i <= 2; i++) {
    setTimeout(function(j) { alert(j) }, 100, i);
}
Примечание. Это не работает в IE9 и ниже браузеров.
ANSWER
Я использую его для анимации для добавления предметов в корзину. Значок корзины плавает в области корзины с кнопки "добавить" продукта при нажатии:
function addCartItem(opts) {
    for (var i=0; i<opts.qty; i++) {
        setTimeout(function() {
            console.log('ADDED ONE!');
        }, 1000*i);
    }
};
ПРИМЕЧАНИЕ. Продолжительность в единицах времени n epocs.
Итак, начиная с момента клика, epoc анимации (из каждой анимации) является произведением каждого односекундного блока, умноженного на количество элементов.
epoc: https://en.wikipedia.org/wiki/Epoch_ (reference_date)
Надеюсь, это поможет!
Вы можете использовать метод bind
for (var i = 1, j = 1; i <= 3; i++, j++) {
    setTimeout(function() {
        alert(this);
    }.bind(i), j * 100);
}
Ну, другое рабочее решение, основанное на ответе Коди, но немного более общее может быть примерно так:
function timedAlert(msg, timing){
    setTimeout(function(){
        alert(msg);    
    }, timing);
}
function yourFunction(time, counter){
    for (var i = 1; i <= counter; i++) {
        var msg = i, timing = i * time * 1000; //this is in seconds
        timedAlert (msg, timing);
    };
}
yourFunction(timeInSeconds, counter); // well here are the values of your choice.
У меня была такая же проблема, как только я решил это.
Предположим, что я хочу 12 задержек с интервалом в 2 секунды
    function animate(i){
         myVar=setTimeout(function(){
            alert(i);
            if(i==12){
              clearTimeout(myVar);
              return;
            }
           animate(i+1)
         },2000)
    }
    var i=1; //i is the start point 1 to 12 that is
    animate(i); //1,2,3,4..12 will be alerted with 2 sec delay
настоящее решение здесь, но вам нужно быть знакомым с языком программирования PHP. вы должны смешивать заказы PHP и JAVASCRIPT, чтобы достичь своей цели.
обратите внимание на это:
<?php 
for($i=1;$i<=3;$i++){
echo "<script language='javascript' >
setTimeout(function(){alert('".$i."');},3000);  
</script>";
}
?> 
Он точно делает то, что вы хотите, но будьте осторожны с тем, как сделать рационализацию между Переменные PHP и JAVASCRIPT.