[MCSD 70-480] Zmiennych czas i zakres

JavaScript varami żyje. Zmienne tam są wszędzie i są niemal wszystkim. Jako zmienną możemy zadeklarować liczbę, napis, a nawet funkcję. Do tego oczywiście dojdziemy (i wtedy będzie naprawdę ciekawie), ale dobrze by było poznać podstawy deklaracji, czasu i zakresu życia takich zmiennych.

Mimo, że wydaje się to wszystko być w miarę proste i oczywiste to widziałem, że sporo osób ma problem z określeniem zakresu życia zmiennych w JavaScriptcie. Tak naprawdę to nie dziwię się im. W sumie kto czyta o takich rzeczach jeśli nie ma na celu nauczenia się wszystkiego w JS i zostania Front-Endowcem. Ja takich aspiracji nie miałem i też czytając o tym cieszyłem się, że wszystko co mi się ‚wydawało’, albo co zauważyłem jest faktycznie prawdą.

Deklaracja zmiennych

Jak już wspomniałem na samym początku w JavaScriptcie wszystko jest varem. Varem jest String, Int, Float, obiekt, funkcja. Wszystko. Dlatego deklaracja i inicjalizacja zmiennych jest banalnie prosta i możemy to zrobić niejako na trzy sposoby.

var myVariable;
var x, y, z;
var x=0.0, y=1.0, z=2.0;

W dwóch pierwszych przykładach deklarujemy zmienne, ale nie są one jeszcze ‚żywe’. Przyjmują ulubioną wartość wszystkich którzy mieli kiedykolwiek do czynienia z JavaScriptem, czyli sławny undefined 🙂

Zakres zmiennych

Skoro wiemy jak ożywić zmienne to czas na to żeby wyjaśnić jak długo będą żyć i czym się właściwie będą zajmować.

Wyróżniamy dwa typy zmiennych:

  • globalne
  • lokalne

Czym się różnią? No tym, że globalne są dostępne globalnie na całej stronie, a lokalne tylko w pewnych miejscach. Jednak tym razem nie mogę już powiedzieć as simple as that. Trzeba kilka rzeczy doprecyzować. Ale najpierw przykładowy kod który sobie omówimy.

var globalVar = "global";
    window.onload = function () {
        var localVar = "local";
        document.getElementById("Div1").onclick = function () {
            var insideDiv1Click;
            //Do some logic here...
            };
        document.getElementById("Div2").onclick = function () {
            };
        document.getElementById("Div3").onclick = function () {
            };
        function AFunction() {
            var x;
            }
        function BFunctionWithParam(p) {
            }
    }

No i tutaj już będzie zaraz wszystko widać o co mi chodziło. Zacznijmy od przypadku najprostszego. globalVar napisany w pierwszej linijce naszego kodu jest zmienną globalną. Oznacza to, że zmienna ta będzie dostępna wszędzie na tej stronie. Podkreślam wszędzie. W każdym skrypcie na tej stronie. Nie tylko w tym co zostało napisane, ale jakby wrzucić jeszcze jeden skrypt pod wszystkimi divami to tam też można by było skorzystać z globalVar.

No a teraz zmienne lokalne.

Wszystko co znajduje się w jakiejś funkcji jest dla nas zmienną lokalną. Pierwszym przykładem jest dla nas localVar. Zmienna ta będzie dla nas dostępna w funkcji przypisanej do onload naszej strony i wszystkich funkcjach podrzędnych (tych które stworzymy w tej funkcji. W związku z tym kiedy napiszemy taki kod:

document.getElementById("Div1").onclick = function () {
    var insideDiv1Click = "insideDiv1";
    alert(globalvar);
    alert(localVar);
    alert(insideDiv1Click);
};

w funkcji będącej event handlerem dla onclicka na Div1 to wszystkie alerty wyświetlą nam taką wartość dla tych zmiennych jaką im przypisaliśmy.

Łatwo się w takim razie domyślić, że jeżeli dla Div2 napiszemy podobny handler na kliknięcie:

document.getElementById("Div2").onclick = function () {
    alert(globalVar);
    alert(localVar);
    alert(insideDiv1Click);
};

To dostaniemy tylko 2 pierwsze alerty takie jakich oczekujemy. Zmienna insideDiv1Click była zdefiniowana w innej funckji, która nie jest nadrzędną dla handlera Div2 dlatego jej zakres tutaj nie sięga.

No i pozostał nam ostatni przykład:

document.getElementById("Div3").onclick = function () {
    var insideDiv3 = "Div3";
    AFunction();
    BFunctionWithParam(insideDiv3);
};
function AFunction() {
    var x;
    alert(insideDiv3);
}
function BFunctionWithParam(p) {
    alert(p);
    alert(localVar);
}

W tym przypadku w handlerze onclick wywołujemy 2 funkcje. W AFunction() próbujemy wyświetlić insideDiv3 co oczywiście nam się nie udaje, ponieważ funkcja ta jest poza zakresem handlera i zmienne lokalne nie mają tutaj swojego zakresu. W BFunctionWithParam(p) przesyłamy sobie do funkcji zmienną lokalną i dzięki temu możemy ją wyświetlić. I to jest jedyny sposób na to żeby zmienne lokalne z jednej funkcji wyświetlić w zupełnie innej.

Unikanie przestrzeni globalnej (global namespace)

Istnieje w Java Scripcie coś takiego jak przestrzeń globalna. To tam siedzą sobie wszystkie natywne biblioteki i stamtąd mamy do nich dostęp. W większości przypadków przestrzeń ta zdefiniowana jest w obiekcie window. Wszystko co tam sobie siedzi jest globalne i dostępne absolutnie z każdego miejsca w kodzie.

Teoretycznie możemy do obiektu window dopisywać swoje rzeczy. ALE!!! Oczywiście jest to mocno nie zalecane. Tak naprawdę przy pisaniu nowych bibliotek z naszymi funkcjami dobrą praktyką jest stosowanie przestrzeni o odwróconym adresie strony np. com.microsoft, albo pl.kduszynski. Z doświadczenia wiem, że w firmach, które tworzą strony często stosuje się też przedrostek nazwy firmy. Dzięki zastosowaniu takiej przestrzeni nazw mamy pewność, że nasze funkcje czy obiekty nie nadpiszą jakiś innych globalnych funkcji.

Ukochany this

Zacznę od przykładu znowu:

this.navigator.geolocation
window.onload = function () {
    //Here, "this" references the window object
    this...
    document.getElementById("aDiv").onclick = function(){
        //Here, "this" references the DIV element
        this…
    }
}

A teraz słowo wstępu. Ostatnio usłyszałem, że jeżeli ktoś jest w stanie opisać czym jest this w jednym zdaniu to nie ma zielonego pojęcia czym to jest. Ja tylko pokrótce i pobieżnie. this jest referencją do obiektu, którego kontekst rozpatrujemy w aktualnej linijce kodu. W naszym przykładzie pierwszy this odnosi się do przestrzeni window, następny dokładnie tak samo i dopiero ostatni w handlerze odnosi się do obiektu aDiv, który pobraliśmy i dla którego tworzymy tę funkcję.

No i to tyle. Tak jak wspomniałem tylko pokrótce, bo absolutnie nie czuję się w tym ekspertem.

Related posts