Zasięg zmiennych – domknięcia JS

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

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

alert(x);
example();[/javascript]

Powyższy kod wyświetli:

[text]10
To w ogóle inny typ![/text]

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

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

Wynik?

[text]To jest moja wartość
To jest moja wartość
undefined[/text]

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:\

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

wynik:

[text]undefined
2[/text]

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:)

[javascript]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);[/javascript]

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]<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>[/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:

[javascript](function($) {

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

})(jQuery);[/javascript]

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ć

Jedna odpowiedź do “Zasięg zmiennych – domknięcia JS”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *