2010-10-17 13 views
6

Próbuję stopniowo zwiększać licznik. Następujące prace:Zamknięcie Javascript "przechowuje" wartość w niewłaściwym czasie

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

Używa jednak niejawnego eval. Zło! Zamiast tego użyjmy zamknięcia, prawda?

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

Oczywiście to nie działa. Wszystkie utworzone zamknięcia wychwytują ostatnią wartość, jaką miał diff w funkcji - 1. Dlatego wszystkie anonimowe funkcje zwiększą licznik o 1, a na przykład _award(100) zwiększą wynik o 28 zamiast tego.

Jak zrobić to poprawnie?

Odpowiedz

10

Jest to znany problem. Ale można łatwo tworzyć zamknięcie na każdej iteracji pętli:

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

Za pomocą Functional.js można utworzyć funkcję przechodzenia do 'setTimeout()' w ten sposób: '_change_score_by.saturate (diff)' i nie potrzebujesz anonimowej funkcji. – Pointy

+0

Sądzę, że musiałbyś również przekazać 'step' jako parametr? – badp

+1

@adres nr _setTimeout (param1, param2) _ jest wykonywany właśnie w tej chwili. Tylko "wewnątrz" funkcji _param1_ nie jest oceniane (jest wykonywane później, jak zauważyłeś w swoim wpisie). –

2

Nikita's approach prace, ale osobiście wolę zmieniając go tym bardziej jednoznaczny sposób (dzięki!):

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

rozwiązując Zamknięcie pętli problem dostaje mniej niechlujny z Function#bind metody ECMAScript piąta edycja za:

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

można hack this feature do przeglądarek, które nie obsługują go y et, aby uzyskać teraz korzyść.

Powiązane problemy