Blog webdeveloperski Patryk yarpo Jar

Zasięg zmiennych – domknięcia JS

Autor wiadomości Styczeń 20, 2011

Javascript jak każdy znany mi język programowania posiada zmienne. Posiada także zasięg zmiennych. Jednak dla programistów przyzwyczajonych do C (Javy, C++, C#) zasada działania zasięgu zmiennych może okazać się mylna...

Prosty kod

var x = 10;
function example()
{
    var x = "To w ogóle inny typ!";
    alert(x);
}

alert(x);
example();

Powyższy kod wyświetli:

10
To w ogóle inny typ!

Póki co żadnych niespodzianek. Czego jednak spodziewasz się w takim wypadku:

function example()
{
    for (var i = 0; i < 1; i++)
    {
        var x = "To jest moja wartość";
        alert(x);
    }
    alert(x);
}
example();
alert(x);

Wynik?

To jest moja wartość
To jest moja wartość
undefined

O ile 3 alert nie powinien nikogo dziwić, to drugi jest niespodzianką. W JavieScript klamry w pętlach nie tworzą zasięgu. Raz stworzona zmienna jest widoczna do końca funkcji [jeśli jest stworzona poza funkcją, to jest zmienną globalną, lub należy do wyższego domknięcia].

Inny problem

Ciekawe, czy prawidłowo określisz, co zostanie wyświetlone w alertach z takiego kodu:\

var x = 10;
function example2()
{
    alert(x); // 1
    var x = 2; // 2
    alert(x); // 3
}
example2();

wynik:

undefined
2

Skąd taki wynik? W funkcji definiujemy po raz kolejny zmienną `x', co sprawia, że w tym domknięciu (domknięciu funkcji `example2') mamy lokalne `x'. W linii "1" `x' ma zatem wartość `undefined', w "2" przypisujemy dopiero odpowiednią wartość i w linii "3" zostaje ona wyświetlona.

Dylemat

Co jednak, kiedy chcesz stworzyć zasięg? Czy na pewno nie ma jakiegoś wytrychu? Skoro zadaje to pytanie, to z pewnością odpowiedź brzmi "tak". W C starczyło stworzyć nowy blok kodu objęty klamrami... A w JS?

Tworzenie "bloku" kodu

Starczy stworzyć anonimową funkcję w funkcji. Funkcja tworzy nowy zasięg. Można ją od razu wywołać. Nie jestem pewien, czy nie zwalnia to skryptu (pewnie tak), jest jednak często sposobem na wredny zasięg zmiennych:)

function example()
{
    (function() {
        for (var i = 0; i < 1; i++)
        {
            var x = "To jest moja wartość";
            alert(x);
        }
    })(); // operator wywołania funkcji, powoduje automatyczne wywołanie funkcji anonimowej

    alert(x);
}
alert(x);

Działanie takiego kodu będzie mniejszą niespodzianką dla programistów z doświadczeniem w językach dziedziczących po C. Jednak powyższe zastosowanie uważam za niepotrzebne (w końcu po co 90% kodu funkcji ma być inną funkcją? Nie lepiej dać po prostu inną nazwę zmiennej?)

Rozsądne zastosowanie

Często jest tak, że mamy kod HTML z fragmentem JS:

<html>
<head>
    <title>Przykład z yarpo.pl</title>
    <script type="text/javascript">
    var x = {'a' : 10, 'b': -1};
    (function(obj) {
       // mamy tu własny zasięg, i  możemy bezpieczniej używać zmiennych
       alert(obj.a);
    })(x); // ... przekazując je jako parametry do funkcji anonimowej
    </script>
</head>
</html>

Taki kod pozwala nam poczuć się choćby trochę bezpieczniej. Gdy załączasz wiele plików JS z różnych źródeł, w końcu nastąpi konflikt nazw. Warto zatem zabezpieczyć się choćby w ten sposób (lepiej jest użyć przestrzeni nazw, ale o tym kiedy indziej). Do naszego skryptu przekazujemy tylko te zmienne, które uważamy za niezbędne. Pozostałe też - jako zmienne globalne będą w anonimowej funkcji widoczne. Jeśli jednak każdą deklarację zmiennej poprzedzisz słowem kluczowym 'var' to twoje zmienne nie nadpiszą wartości globalnych.

To rozwiązanie często wykorzystywane jest w takim celu:

(function($) {

// tu mam dostęp do jQuery za pomocą $

})(jQuery);

Wiele skryptów tworzy obiekty wykorzystując właśnie nazwę $. Dlatego twórcy jQuery zdecydowali się na trzymanie referencji do frameworka w zmiennej o nazwie 'jQuery'. Wewnątrz naszej anonimowej funkcji pod zmienną o nazwie $ na pewno zawsze będziemy mieli jQuery. Warto, różne rzeczy w JS są możliwe 🙂 Zarówno dobre, jak i złe 🙂

Z domknięciami silnie skojarzone jest pojecie "hoistingu". Warto także o nim poczytać.

Warto przeczytać

Komentarze (1) Trackbacks (0)
  1. Dzięki wielkie ! 🙂 fajnie to wytłumaczyłeś na przykładach 🙂


Leave a comment

 

Brak trackbacków.