2010-10-17 16 views
6

Sto provando ad aumentare gradualmente il contatore. I seguenti lavori:chiusura Javascript valore "memorizza" nel momento sbagliato

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

Tuttavia, utilizza una valutazione implicita. Il male! Usiamo invece una chiusura, giusto?

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

Ovviamente, questo non funziona. Tutte le chiusure create catturano l'ultimo valore nella funzione: diff - 1. Quindi tutte le funzioni anonime aumenteranno il contatore di 1 e, ad esempio, _award(100) aumenterà invece il punteggio di 28.

Come posso farlo correttamente?

risposta

10

Questo è un problema noto. Ma è possibile creare facilmente una chiusura su ogni iterazione del ciclo:

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

Utilizzando Functional.js è possibile creare la funzione per passare a 'setTimeout()' in questo modo: '_change_score_by.saturate (diff)' e non sarebbe necessaria la funzione anonima. – Pointy

+0

Immagino che dovresti passare anche 'step' come parametro? – badp

+1

@badp No. _setTimeout (param1, param2) _ viene eseguito proprio in questo momento. Solo 'inside' della funzione _param1_ non viene valutato (viene eseguito in seguito, come hai notato nel tuo post). –

2

Nikita's approach opere, ma personalmente preferisco cambiare a questo modo più esplicito (grazie!):

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

Risolvere il Loop Problema chiusura ottiene meno disordinato con Function#bind il metodo di ECMAScript Quinta edizione:

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

Puoi hack this feature nei browser che non supportano lo y et per ottenere il beneficio ora.

Problemi correlati