2012-04-10 11 views
14

Czy istnieje określone źródło przechwytywania zmiennych w Javascriptu poza standardem (odczytanie standardu jest bolesne?)Zrozumienie przechwytywania zmiennych przez zamknięcia w języku JavaScript/węźle

W poniższym kodzie i jest kopiowany przez wartość:

for (var i = 0; i < 10; i++) 
{ 
    (function (i) 
    { 
     process.nextTick(function() 
     { 
      console.log(i) 
     }) 
    }) (i) 
} 

Więc drukuje to 1..10. process.nextTick jest analogiem setTimeout(f,0) w węźle.

Ale w następnym kodu i nie wydają się być kopiowane:

for (var i = 0; i < 10; i++) 
{ 
     var j = i 
     process.nextTick(function() 
     { 
      console.log(j) 
     }) 
} 

Drukuje 9 10 razy. Czemu? Bardziej interesuje mnie artykuł referencyjny/ogólny niż wyjaśnienie tego konkretnego przypadku przechwytywania.

Odpowiedz

6

Nie mam przydatnego odniesienia. Najważniejsze jest jednak: W pierwszym przypadku jawnie przechodzisz w i do anonimowej funkcji, która tworzy nowy zakres. Nie tworzysz nowego zakresu dla i lub j w drugim. Ponadto JavaScript zawsze przechwytuje zmienne, a nie wartości. Więc będziesz mógł modyfikować również.

Słowo kluczowe JavaScript var ma zasięg funkcji, a nie zakres blokowy. Tak więc pętla for nie tworzy zakresu.

Uwaga: niestandardowe słowo kluczowe let ma zasięg lokalny.

+0

nie jest jasne, dlaczego ja nie tworząc nowe możliwości j – nponeccop

+0

@nponeccop, JavaScript posiada zakres funkcji. –

+0

Uderzam głową w stół. Nie wiedziałem tego, założyłem, że jest to C++ lub Perl lub Haskell :) Fascynujący – nponeccop

4

Jest on kopiowany (lub przypisywany) w drugim przykładzie, jest tylko jeden egzemplarz zmiennej j i będzie miał wartość, która miała w nim ostatni, który będzie wynosił 9 (ostatni obrót twojej pętli for). Potrzebujesz nowego zamknięcia funkcji, aby utworzyć nową kopię zmiennej dla każdego obrotu pętli for. Twój drugi przykład ma tylko jedną zmienną, która jest wspólna dla wszystkich obrotów twojej pętli for, więc może mieć tylko jedną wartość.

Nie znam żadnego ostatecznego zapisu na ten temat.

Zmienne w javascript są ograniczone do poziomu funkcji. W javascript nie ma zakresu blokowego. W związku z tym, jeśli chcesz nową wersję zmiennej dla każdego rev pętli for, musisz użyć nowej funkcji (tworzenie zamknięcia funkcji), aby przechwytywać tę nową wartość za każdym razem przez pętlę for. Bez zamknięcia funkcji jedna zmienna będzie miała tylko jedną wartość, która będzie wspólna dla wszystkich użytkowników tej zmiennej.

Kiedy deklarujesz zmienną takich jak var j = i; w pewnym miejscu innym niż na początku funkcji, JavaScript wciągarek definicję na górę funkcji i kod staje się odpowiednikiem tego:

var j; 
for (var i = 0; i < 10; i++) 
{ 
     j = i; 
     process.nextTick(function() 
     { 
      console.log(j) 
     }) 
} 

ten nazywa się variable hoisting i jest to termin, który możesz nazwać Google, jeśli chcesz przeczytać więcej na jego temat. Ale chodzi o to, że istnieje tylko zakres funkcji, więc zmienna zadeklarowana gdziekolwiek w funkcji jest faktycznie zadeklarowana raz na górze funkcji, a następnie przypisana do dowolnego miejsca w funkcji.

+0

Zaktualizowano moją odpowiedź, podając więcej szczegółów na temat Twojej sytuacji. – jfriend00

4

W JavaScript, funkcje obejmują zmienne, które zostały zdefiniowane w zakresie poza własnym w taki sposób, że mają "żywe" odniesienie do zmiennej, a nie migawkę jej wartości w danym czasie.

Więc w drugim przykładzie można utworzyć dziesięć funkcji anonimowy (w process.nextTick(function(){...})), które otaczają zmienna j (i i, które zawsze mają taką samą wartość, gdy funkcja jest tworzony anonimowy). Każda z tych funkcji używa wartości j w czasie po zewnętrzna pętla for została uruchomiona w całości, więc j=i=10 w momencie wywołania każdej z funkcji. To znaczy, że twoja pętla for działa całkowicie, wtedy twoje anonimowe funkcje działają i używają wartości j, która jest już ustawiona na 10!

W pierwszym przykładzie sytuacja wygląda nieco inaczej. Owijając wywołanie process.nextTick(...) w jego własnej funkcji anonimowej i wiążąc wartość i w zakresie funkcji lokalnego poprzez wywołanie funkcji otoki (i nawiasem mówiąc shadowing stary zmienna i w parametrze funkcji i), przechwytywanie wartości zmiennej i w tej chwili momencie, zamiast zachowania zamkniętego odniesienia do i, którego wartość zmienia się w obudowie anonimowych funkcji wewnętrznych.

Aby nieco wyjaśnić swój pierwszy przykład, spróbuj zmienić anonimową funkcję opakowania, aby użyć argumentu o nazwie x ((function (x) { process.nextTick(...); })(i)). Tutaj wyraźnie widać, że x przyjmuje wartość w i w momencie wywołania funkcji anonimowej, dzięki czemu otrzyma każdą z wartości w pętli for (1..10).

+0

Jakie jest najlepsze rozwiązanie do przechwytywania wartości zamiast zachowania załączonego odniesienia? –

Powiązane problemy