Bloki i zakres widoczności zmiennych
Blokiem kodu nazywamy ciąg instrukcji zawartych w nawiasach klamrowych {}
. Może to być ciało funkcji albo blok wykonywany w instrukcjach złożonych. Jedną z najważniejszych zasad funkcjonowania bloków, jest widoczność zadeklarowanych w nich zmiennych.
Przykład:
> if (true) {
var v=1;
const c=1;
let l=1;
}
> v
1
> l
ReferenceError: l is not defined
> c
ReferenceError: c is not defined
>
Widzimy, że zmienna zadeklarowana słowem var jest widoczna poza blokiem w którym to wykonaliśmy (caiło instrukcji if), gdy tymczasem w przypadku let i const - mamy widoczność jedynie w obrębie ciała instrukcji/funkcji. W Javascript operuje się często pojęciem domknięcia (clousre) - które określa w jakim bloku jest zamknięta nasza zmienna. W przypadku zmiennych var domknięcie tworzą jedynie funkcje. Warto przy tym zwrócić uwagę na niebezpieczeństwo związane z zagnieżdżaniem bloków. Przeanalizujmy poniższy kod:
> var kolor1='red';
> var kolor2='blue';
> function komunikat(msg) {
var kolor1='yellow';
kolor2='black';
console.log(msg,kolor1,kolor2);
}
> console.log(kolor1,kolor2);
red blue
> komunikat('OK');
yellow black
> console.log(kolor1,kolor2);
red black
Wykonanie funkcji komunikat
spowodowało zmianę wcześniej zadeklarowanej zmiennej kolor2, gdy tymczasem kolor1 zmienił się jedynie w ciele funkcji. Różnica bierze się z tego, że w ciele funkcji zadeklarowano zmienną lokalną kolor1 (użycie słowa kluczowego var). Tymczasem zmienna kolor2 jest zadeklarowana tylko raz i ona jest uzywana zarówno w ciele funkcji jak i na zewnątrz (jest to ta sama zmienna).
Problem w tym, że deklaracja zmiennej w Javascript następuje przy pierwszym jej użyciu i brak var w przypadku kolor2='black';
mógł wynikać z omyłkowego ominięcia var!
Tego problemu nie ma w trybie ścisłym ( "strict") skryptów. Wymagana jest wówczas pełna deklaracja zmiennych.
Poniższy skrypt zakończy się błędem - gdyż w pierwszej linii włączamy tryb ścisły:
"use strict";
a=1; // brakuje słowa var let lub const
Hoisting
Przyjrzyjmy się przykładowi:
function komunikat(msg) {
if (kolor===undefined) {
var kolor='black';
}
console.log(msg,kolor);
}
komunikat('OK');
W warunku instrukcji if sprawdzamy, czy zmienna kolor ma wartość niezdefiniowną. Jednak ta zmienna nie została jeszcze w ogóle zadeklarowana - dzieje się to w wierszu następnym. Czyli mamy do czynienia z błędem? Nie - gdyż zmienne zadeklarowane z użyciem słowa kluczowego var są widoczne w obrębie całej funkcji, w której znajduje się deklaracja (jeśli poza funkcją - deklarujemy tak zmienne globalne). Nazywa się to hoistingiem (http://poradnik.drogimex.pl/2017/05/20/hoisting-zmiennych-i-funkcji-w-javascript/, https://www.nafrontendzie.pl/zakres-zmiennych-javascript).
Nie dotyczy to zmiennych deklarowanych przy użyciu let i const. One są widoczne dopiero po zadeklarowaniu. Zmiana var w powyższym przykładzie na let/const powoduje błąd.