wtorek, 23 października 2012

zasieg zmiennych (scope) w JavaScript

Czytam sobie ostatnio do poduszki obiektowy JS, tak w ramach powtorzenia. Poniewaz dziergam w tym jezyku kilka lat juz coraz mniej mnie dziwi. Aczkolwiek kwestia, z ktora sobie dosc dlugo nie moglam poradzic byl zasieg zmiennych.

Zalozmy ze mamy kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   var a = 2;
   console.log('2. ' + a);
}

f();

Zasieg zmiennych w JS jest ograniczony nie do nawiasow klamrowych, a do funkcji (od ES6 tylko dla słowa kluczowego var). Jesli zmienna jest w globalnej przestrzeni nazw (bez slowka var) to jest osiagalna praktycznie z dowolnego miejsca. Slowko var ogranicza zasieg, np do danego pliku czy funkcji.

Co bedzie wynikiem dzialania takiego kodu? Otoz zmienne sa widoczne w srodowiskach zawartych, ale nie na zewnatrz. Wiec jesli na zewnatrz funkcji mamy zdefiniowana zmienna a, a wewnatrz funkcji tworzymy ja jeszcze raz (slowko var), to JavaScript bedzie widzialo ta zmienna wewnatrz funkcji, jako zmienna o zasiegu tylko na te funkcje. Zaskutkuje to tym, ze pierwszy console.log wypisze nam undefined. Dlaczego? Bo wewnatrz funkcji ta zmienna JESZCZE nie ma wartości (interpreter już wie, że będzie stworzona, ale jeszce w tej linii kodu nie ma wartości; stąd dobra praktyka tworzyć WSZYSTKIE zmienne na początku funkcji/bloku kodu, żeby uniknąć takich sytuacji), wiec by default ma przypisana wartosc undefined. Drugi console.log wypisze juz, zgodnie z oczekiwaniami wartosc 2.


Zmodyfikujmy troche nasz kod:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

f();

Mala roznica. Wenatrz funkcji usunelam slowo var przed definicja zmiennej lokalnej a. Co to zmienia z punktu widzenia naszego programu? Wszystko. Przede wszytkim JavaScript sprawdzi, czy w zasiegu dostepnym z wnetrza funkcji nie ma juz zmiennej a. Jesli jest (jak w naszym przypadku) to zmieni jej wartosc.

Nasz program wypisze dwa razy wartosc zmiennej a widoczna wewnatrz funkcji. Za pierwszym razem bedzie to 1, a za drugim 2 (wartosc zmieniona juz wewnatrz funkcji)


To teraz tylko sprawdzenie, jak to wyglada na zewnatrz funkcji:
var a = 1;
function f() {
   console.log('1. ' + a);
   a = 2;
   console.log('2. ' + a);
}

console.log('3. ' + a);

f();

console.log('4. ' + a);

Zgodnie z oczekiwaniami zmienna istnieje w kazdym przypadku i zmiana jej wartosci wewnatrz funkcji skutkuje zmiana rowniez poza funkcja, bo operujemy na zmiennej o zakresie szerszym niz zakres tej funkcji.

3 komentarze:

  1. Przygotowuję się do rozmowy kwalifikacyjne, pomocny artykuł, dzięki :)

    OdpowiedzUsuń
  2. Dzień dobry interpretacja działania pierwszego przykładu jest nieprawidłowa. undefined oznacza, że WARTOSC jest niezdefiniowana, ale zmienna jak najbardziej istnieje w scope funkcji i to wynika z hoistingu w javascript.

    OdpowiedzUsuń