2010-10-17 4 views
6

Ich versuche, einen Zähler schrittweise zu erhöhen. Folgendes funktioniert:Javascript Verschluss "speichert" Wert zur falschen Zeit

function _award(points){  
    var step = 1; 
    while(points){ 
    var diff = Math.ceil(points/10); 
    setTimeout("_change_score_by("+diff+");" /* sigh */, 
       step * 25); 
    points -= diff; 
    step++; 
    } 
} 

Es verwendet jedoch eine implizite Bewertung. Böse! Lass uns stattdessen einen Verschluss benutzen, oder?

function _award(points){  
    var step = 1; 
    while(points){ 
    var diff = Math.ceil(points/10); 
    setTimeout(function(){ _change_score_by(diff); }, 
       step * 25); 
    points -= diff; 
    step++; 
    } 
} 

Offensichtlich funktioniert das nicht. Alle erzeugten Schließungen fangen den letzten Wert ein, den diff in der Funktion - 1 hatte. Daher erhöhen alle anonymen Funktionen den Zähler um 1, und zum Beispiel wird _award(100) die Punktzahl um 28 erhöhen.

Wie kann ich das richtig machen?

Antwort

10

Dies ist ein bekanntes Problem. Aber man kann leicht einen Verschluss auf jeder Schleife Iteration erstellen:

(function(current_diff) { 
    setTimeout(function() {_change_score_by(current_diff);}, 
       step * 25); 
})(diff); 
+0

Mit Functional.js könnten Sie die Funktion erstellen, die so an 'setTimeout()' übergeben wird: '_change_score_by.saturate (diff)' und Sie würden die anonyme Funktion nicht benötigen. – Pointy

+0

Ich denke, Sie müssten dann auch "Schritt" als Parameter übergeben? – badp

+1

@badp Nr. _setTimeout (param1, param2) _ wird in diesem Moment ausgeführt. Nur 'inside' der Funktion _param1_ wird nicht ausgewertet (es wird später ausgeführt, wie Sie in Ihrem Beitrag notiert haben). –

2

Nikita's approach funktioniert, aber persönlich ziehe ich es auf diese explizite Weise zu ändern (Danke!):

function _schedule_score_change(diff, step){ 
    setTimeout(function(){ _change_score_by(diff) }, 
       step*25); 
} 

function _award(points){  
    var step = 1; 
    while(points){ 
    var diff = Math.ceil(points/10); 
    _schedule_score_change(diff, step); 
    points -= diff; 
    step++; 
    } 
} 
3

Lösen das Closure-Schleife Problem unordentlich wird weniger mit ECMAScript Fifth Function#bind Methode der Ausgabe:

setTimeout(_change_score_by.bind(window, diff), step*25); 

Sie hack this feature in Browsern kann, dass es nicht y unterstützen um jetzt den Vorteil zu bekommen.

Verwandte Themen