Sytuacja kobiet w IT w 2024 roku
22.04.20204 min
Harrison Grant-Favor

Harrison Grant-FavorSoftware Engineer

var, let i const - hoisting i zasięg w JavaScript

Poznaj właściwości słów kluczowych var, let oraz const w JavaScript. Zobacz, jak w każdym przypadku działa hoisting i jaki mają zasięg.

var, let i const - hoisting i zasięg w JavaScript

JavaScript, podobnie jak wiele z tych bardziej nowoczesnych języków programowania, zapewnia szereg metod deklaracji zmiennych. W JS można ich dokonywać za pomocą słów kluczowych var, let i const. Każde z nich ma swoje przeznaczenie. Artykuł ten ma na celu omówienie różnic i niuansów związanych z używaniem każdej z metod. Dla lepszego zapoznania się z tematem sprawdź definicje każdego z tych słów kluczowych w oficjalnej specyfikacji ECMAScript i MDN.

Słowo kluczowe var deklaruje zmienną o aktualnym kontekście wykonania, wraz z opcjonalnym zaincjalizowaniem wartością.
Słowo kluczowe let deklaruje zmienną w zasięgu bloku, wraz z opcjonalnym zaincjalizowaniem wartością. 
Słowo kluczowe const deklaruje stałe w zasięgu bloku, podobne do słowa kluczowego let, ale nie można zmienić wartości tej stałej. Deklaracja const tworzy referencję typu read-only do wartości.

Windowanie (ang. Hoisting)

Jako koncept, hoisting sugeruje, że zmienne i deklaracje funkcji są przenoszone, tak aby znalazły się na początku Twojego kodu. Co się jednak naprawdę dzieje to to, że deklaracje zmiennych i funkcji są zapisywane w pamięci podczas fazy kompilacji, ale pozostają dokładnie tam, gdzie zostały wpisane w kodzie. Podstawowe znaczenie windowania polega na tym, że umożliwia ono korzystanie z funkcji przed zadeklarowaniem ich w kodzie.

Oto rzeczy, których możemy nauczyć się z definicji windowania.

  • Co zostaje przeniesione, to deklaracje zmiennych i funkcji. Przypisanie zmiennych i inicjalizacja nigdy nie zostaje przeniesiona.
  • Deklaracje nie są przenoszone na początek kodu; zamiast tego są zapisywane w pamięci.


W JavaScript wszystkie zmienne zdefiniowane przy użyciu var na początku mają wartość undefined. Jest to spowodowane windowaniem, które zapisuje w pamięci deklaracje zmiennych i inicjuje je wartością undefined. Poniższy przykład dobrze to ilustruje:


Linijka 2 wyrzuca ReferenceError: y is not defined


Jednak zmienne zdefiniowane za pomocą słów kluczowych let i const, gdy są windowane, nie są inicjalizowane z undefined. Są one raczej w stanie zwanym Temporal Dead Zone, dopóki ich definicje nie zostaną zewaluowane.


Linijka 1 wyrzuca ReferenceError ponieważ nadal znajduje się w Temporal Dead Zone

Następny fragment kodu pokazuje hoisting zmiennych let i const.


Linijka 3 wyrzuca ReferenceError, ponieważ x w linijce 4 zostało wywindowane wewnątrz bloku 

Zmienna x zdefiniowana w bloku za pomocą słowa kluczowego let jest windowana i ma pierwszeństwo przed zmienną x zdefiniowaną za pomocą var. Jednak nadal znajduje się ona w Temporal Dead Zone, gdy występuje odwołanie do niej z console.log(x), a zatem wyrzuca reference error.

Zasięg

Zmienne zdefiniowane za pomocą słowa kluczowego var mają zasięg, który jest ich bieżącym kontekstem wykonania. Nie mają one zasięgu blokowego, więc można uzyskać do nich dostęp spoza bloku, w którym zostały zdefiniowane. Może się tak stać pod warunkiem, że zmienne te nadal znajdują się w zasięgu kontekstu wykonania. Zmienne let i const mają jednak zasięg blokowy i nie można uzyskać do nich dostępu spoza bloku. Widać to poniżej:


Do niektórych zmiennych można się odwołać poza ich zasięgiem

Ponadto, gdy deklarujesz zmienną globalną ze słowem kluczowym var, to zostaje ona dołączona do kontekstu globalnego (window w przeglądarce i global w Node.js). Nie dzieje się tak w przypadku zmiennych globalnych zadeklarowanych za pomocą let i const.

Warto zapamiętać

  • Gdy po prostu przypiszesz wartość do zmiennej, bez deklaracji za pomocą słów kluczowych, zmienna ta zostaje utworzona i dołączona do globalnego kontekstu wykonania (window w przeglądarce i global w Node.js). Robienie tego nie jest jednak zalecane, ponieważ znacznie utrudnia to debugowanie.


Zmienne zostają dołączone do kontekstu globalnego

  • Zmienne zadeklarowane za pomocą słowa kluczowego var mogą być ponownie zadeklarowane w dowolnym momencie kodu, nawet jeśli są w tym samym kontekście wykonania. Nie dotyczy to zmiennych zdefiniowanych za pomocą słów kluczowych let i const, ponieważ można je zadeklarować tylko raz w ramach ich zasięgu leksykalnego.


Nie można ponownie zadeklarować zmiennych let i const

Może się pojawić wtedy problem, zwłaszcza, jeśli używasz let lub const do deklarowania zmiennej wewnątrz switch.


W obu przypadkach, foo znajduje się w tym samym bloku


Oczywiście można tego uniknąć, używając nawiasów klamrowych wokół case'ów, aby zdefiniować różne bloki, ale prawdopodobnie należałoby to zrefaktoryzować.


W obu przypadkach, foo znajduje się w różnych zasięgach blokowych

  • Kolejną kwestią, o której warto pamiętać to fakt, że mimo iż nie można przypisać ponownie wartości do stałej, to nadal jest ona mutowalna. Dobrze można to zilustrować faktem, że jeśli wartością jest obiekt, właściwości obiektu będzie można modyfikować.


Zmienne zdefiniowane za pomocą const nadal można modyfikować

<p>Loading...</p>