2010-10-18 14 views
5

moje pytanie jest w rzeczywistości jednym ze zrozumienia - mam działające rozwiązanie, po prostu nie rozumiem, jak to działa.Zmienny globalny zakres zrozumienia pytania

Okay, więc - próbuję to zrobić, dodając setTimeout w pętli i przekazując zmieniającą się wartość przez niego. Przykład:

for (i=0;i<11;i++) 
{ 
    setTimeout("alert(i)",1000); 
} 

Jeśli rozumieć prawidłowo praca ta nie robi ponieważ JavaScript nie (jak PHP) przechodzi wartość i do funkcji, ale przechodzi przez odniesienie I - która z kolei nie jest statyczny, lecz nadal zmienić z licznikiem.

znalazłem rozwiązanie, które idzie tak:

for (i=0;i<11;i++) 
{ 
    setTimeout(function(x){return function(){alert(x)};}(i),1000); 
} 

I naprawdę nie rozumiem, co to właściwie jest. Wygląda na to, że przekazuje funkcję "alertu" z powrotem do funkcji wywołującej, ale nie mogę tego zrozumieć.

Mogę pracować z tym rozwiązaniem, a także dostosować go do innych kontekstów, ale naprawdę chciałbym zrozumieć cały mój kod, a nie tylko użyć rzeczy, które gdzieś znalazłem i być szczęśliwym, że działają. A ponadto szukam szczuplejszej wersji, aby osiągnąć ten sam cel.

Dzięki Marco

+3

+1 za "Naprawdę chciałbym zrozumieć cały mój kod, nie tylko użyć rzeczy, które gdzieś znalazłem i być szczęśliwym, że to działa" –

Odpowiedz

2

Powodem dzwonisz funkcję zwracającą funkcji jest to, że trzeba mieć jakiś sposób dla funkcji jest przekazywana do setTimeout() mieć odniesienie do wartości prąd z i.

Ponieważ kod czeka, aby uruchomić dla 1000ms, pętla for będzie kompletna, zanim skończy, a wartość jeśli i będzie 11.

Ale ponieważ funkcja ma swój własny zakres zmienny, można przekazać wartość i do funkcji, która jest wywoływana natychmiast, tak że odwołuje się do niej lokalna zmienna x, którą zwracana funkcja może odwoływać się, gdy w końcu wywoła ją w postaci setTimeout().

for (i=0; i<11; i++) { 
    setTimeout(function(x){ 
       // CONTINUE HERE: 
       // x is a local variable to the function being executed 
       // which references the current value of i 

       // A function is being returned to the setTimeout that 
       // references the local x variable 
       return function(){ alert(x); }; 

       }(i) // START HERE: 
        // The "outer" function is executed immediately, passing the 
        // current value of "i" as the argument. 
    ,1000); 
} 

Więc kończąc odpowiednika, który byłby mniej więcej tak:

setTimeout(function(){ alert(x); }, 1000); //...where x === 0 
setTimeout(function(){ alert(x); }, 1000); //...where x === 1 
setTimeout(function(){ alert(x); }, 1000); //...where x === 2 
setTimeout(function(){ alert(x); }, 1000); //...where x === 3 
// etc. 
+0

Patrick, dziękuję bardzo. To był prawdopodobnie brakujący link. –

+0

@Marco P. - Nie ma za co. : o) – user113716

4

Co to robi:

function(x){return function(){alert(x)};}(i) 

Czy to ma funkcję:

function(x){ ...code... } 

i wykonuje go natychmiast, przechodząc i (z pętli for) jako jedyny parametr (do czego służy (i)). Ten powraca inna funkcja:

function(){ alert(x); } 

To że wynik że to były przekazywane do setTimeout() jako funkcja it połączeń, gdy interwał czasowy, a nie jest to odwołanie do zmiennej i w swojej pętli, która się zmienia, to przy użyciu kopii, która została przekazana podczas tworzenia nowej funkcji.

+0

Dziękuję za poświęcony czas, aby mi to wyjaśnić - i dziękuję również za "+1". To prawda, cała moja strona (airports.palzkill.de) - z wyjątkiem rzeczy Google - jest tworzona samodzielnie. –

0

Patrick i Nick pomógł mi w zrozumieniu wielkiego całość, więc chciałbym podsumuj to dla wszystkich mających ten sam problem co ja:

setTimeout (jak również niektóre inne funkcje opóźnione czasowo, takie jak eventlistenery) wydaje się przechowywać wywołanie zwrotne jako ciąg znaków, a następnie używa pewnego rodzaju wewnętrznego eval na tym łańcuchu, tak interpretuje to jako kod.

To powoduje problemy z pętlami i opóźnionymi funkcjami, ponieważ ich odniesienie do zmiennej odnosi się do końcowego wyniku tej pętli lub może do zmiennej, która nie jest nawet globalna.

Jak rozumiem, rozwiązanie z funkcja-w-funkcji rozwiązuje ten problem, dając ciąg z powrotem w wyniku funkcji, która następnie zawiera wartość, a nie odniesienie do zmiennej (alert("1") nie alert(i)) .

Jeśli chodzi o skrócenie kodu, mój prosty umysł znalazł proste rozwiązanie. Ponieważ oczekuje się, że zwrotna będzie ciąg, to dlaczego nie napisać wartości zmienne do tego ciągu, a następnie dać ten powrotem:

for (i=0;i<11;i++) 
{ 
    setTimeout("alert("+i+")",1000); 
} 

Obiektywnie Prawdopodobnie nie jest to najlepsze rozwiązanie, ale ponieważ wymaga najmniejszej ilości kod i najmniejsza ilość zasobów mózgowych, aby zrozumieć, jak i dlaczego działa w przeciwieństwie do innych rozwiązań, mogę z tym teraz pracować.

Jeszcze raz dziękuję Patrickowi, Nickowi i nieznanemu facetowi, który wycofał swoją odpowiedź za poświęcenie czasu, aby mi w tym pomóc!

+0

Marco - Masz częściowo rację. 'SetTimeout' może przyjąć łańcuch dla swojego argumentu, który następnie spróbuje' eval'. Jeśli istnieje metoda (taka jak alert) w globalnej przestrzeni nazw, uruchomi się. Ale 'setTimeout' może również zaakceptować obiekt funkcji jako argument. Odbywa się to poprzez przekazanie anonimowej funkcji (którą zwrócił kod w twoim przykładzie) lub przekazanie zmiennej odwołującej się do funkcji. Jeśli funkcja zostanie odebrana, zostanie wywołana w globalnej przestrzeni nazw, niezależnie od tego, że mogła pochodzić z zakresu prywatnego. W js możesz przekazywać funkcje w ten sposób. – user113716