Funktionen in einer Schleife an setTimeout übergeben: immer der letzte Wert?

Lesezeit: 4 Minuten

Funktionen in einer Schleife an setTimeout ubergeben immer der letzte
Dee2000

Ich versuche, setTimeout zu verwenden, um eine anonyme Funktion auszuführen, an die ich Informationen übergebe, und ich habe Probleme. Diese (fest codierte Version) würde gut funktionieren:

setTimeout(function(){alert("hello");},1000);
setTimeout(function(){alert("world");},2000);

Aber ich versuche, das Hallo und die Welt aus einem Array zu nehmen und sie an die Funktion zu übergeben, ohne (a) globale Variablen zu verwenden und (2) eval zu verwenden. Ich weiß, wie ich es mit Globals oder Eval machen könnte, aber wie kann ich es ohne machen. Folgendes würde ich gerne tun (aber ich weiß, dass es nicht funktionieren wird):

var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
    setTimeout( function(){alert(strings[i]);}, delay);
    delay += 1000;
}

Natürlich Saiten[i] wird aus dem Zusammenhang gerissen. Wie kann ich Zeichenfolgen übergeben[i] in diese anonyme Funktion ohne evalu oder globals?

  • Siehe stackoverflow.com/questions/3445855/…

    – kennytm

    21. Juni 11 um 12:17 Uhr

  • Wenn Sie dieselbe Antwort akzeptieren, kehren Sie immer wieder zurück

    – Anand Thanganpan

    21. Juni 11 um 12:22 Uhr

  • mögliches Duplikat des Javascript-Abschlusses innerhalb von Schleifen – einfaches praktisches Beispiel

    – Felix Klinge

    10. März 13 um 08:28 Uhr

Funktionen in einer Schleife an setTimeout ubergeben immer der letzte
Alnitak

Dies ist das sehr häufig wiederholte Problem „Wie verwende ich eine Schleifenvariable in einem Abschluss?“.

Die kanonische Lösung besteht darin, eine Funktion aufzurufen, die eine Funktion zurückgibt, die an den aktuellen Wert der Schleifenvariablen gebunden ist:

var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
    setTimeout(
        (function(s) {
            return function() {
                alert(s);
            }
        })(strings[i]), delay);
    delay += 1000;
}

Die äußere Definition function(s) { ... } erstellt einen neuen Geltungsbereich wo s ist an den aktuellen Wert des angegebenen Parameters gebunden – dh strings[i] – wo es für die verfügbar ist innere Umfang.

  • Die Funktion muss nichts zurückgeben, Sie können das setTimeout in einer haben IIFE

    – qwertymk

    21. Juni 11 um 12:24 Uhr


  • @qwertymk das stimmt, aber ich ziehe es vor, nur den Rückruf zu umbrechen, nicht den Anmeldung des Callbacks, nicht zuletzt, weil es das ist, was normalerweise benötigt wird, wenn man dasselbe für DOM-Event-Handler macht.

    – Alnitak

    21. Juni 11 um 12:25 Uhr


  • @Alnitak: Ich denke, es ist ziemlich üblich, es auf Svintos Art zu machen. Es ist auch leichter zu verstehen, ohne dem Gehirn des Lesers eine weitere Ebene des Spielraums zu geben

    – qwertymk

    21. Juni 11 um 12:32 Uhr

  • @alnitak: benalman.com/news/2010/11/…

    – qwertymk

    21. Juni 11 um 12:52 Uhr

  • @qwertymk, @Alnitak: Bei beiden Ansätzen erstellen Sie wiederholt eine neue, aber identische Funktionsinstanz innerhalb einer Schleife. Besser IMO ist es, eine benannte Funktion außerhalb der Schleife zu erstellen und diese aufzurufen.

    – Benutzer113716

    21. Juni 11 um 13:01 Uhr

Fügen Sie einfach einen Bereich um den Aufruf setTimeout hinzu:

var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
    (function(s){
        setTimeout( function(){alert(s);}, delay);
    })(strings[i]);
    delay += 1000;
}

Sie könnten eine separate Funktion schreiben, um das Timeout einzurichten:

function doTimer(str, delay) {
  setTimeout(function() { alert(str); }, delay);
}

Rufen Sie das dann einfach aus der Schleife auf:

var delay = 1000;
for(var i=0;i<strings.length;i++) {
    doTimer(strings[i], delay);
    delay += 1000;
}

  • Ich kann mich irren, aber das sieht für mich so aus, als ob es unter dem gleichen Problem leiden könnte. Es würde keine Schließung der str-Variablen erzeugen, oder doch? In jedem Fall hinterlässt es eine globale doTimer-Funktion, daher bevorzuge ich die Antwort von Alnitak. Trotzdem danke.

    – Dee2000

    21. Juni 11 um 12:35 Uhr

  • Es übergibt eine Kopie der Referenz, also ist es in Ordnung. Das Problem im Original ist, dass es nur ein “i” gibt, das von allen Timeout-Handlern geteilt wird. Und die Funktion muss nicht global sein – sie kann eine lokale Funktion in jeder Funktion sein, in der sich anderer Code befindet.

    – Spitze

    21. Juni 11 um 12:39 Uhr

  • Wow, ich glaube, das ist die Am besten Antworten

    – iConnor

    22. Juni 13 um 23:20 Uhr

  • warum gehst du nicht einfach als die durch delay -> (i+1) * 1000 ? scheint mir, es ist besser als eine zusätzliche Variable

    – vsync

    22. Oktober 13 um 12:40 Uhr

  • @vsync ja das würde sicherlich funktionieren. (Entschuldigung, ich habe dich am Anfang falsch verstanden.)

    – Spitze

    22. Oktober 13 um 13:09 Uhr

1643724307 901 Funktionen in einer Schleife an setTimeout ubergeben immer der letzte
Ciaran

Obwohl nicht so abwärtskompatibel wie einige der anderen Antworten, dachte ich, ich würde eine andere Option aufwerfen, diesmal mit binden()!

var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
    setTimeout(alert.bind(this, strings[i]), delay);
    delay += 1000;
}

Sehen Sie sich die Demo in Aktion an

var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
    setTimeout( new Function('alert(strings[i]);'), delay);
    delay += 1000;
}

.

728290cookie-checkFunktionen in einer Schleife an setTimeout übergeben: immer der letzte Wert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy