Menu

let, const i var w JavaScript: zakres, hoisting i kiedy czego używać

Trzy sposoby deklarowania zmiennej w JavaScript i dlaczego nowoczesny kod domyślnie używa const, let tylko wtedy, gdy musi, a var praktycznie nigdy.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Trzy słowa kluczowe, jedno zadanie

JavaScript ma trzy sposoby deklarowania zmiennej: var, let i const. Wszystkie wiążą nazwę z wartością, ale różnią się zakresem, zasadami ponownego przypisania i zachowaniem przed wykonaniem deklaracji. Nowoczesny kod przez większość czasu używa const, let wtedy, gdy wartość musi się zmieniać, a var rzadko albo wcale.

W skrócie:

Reszta tej strony wyjaśnia, dlaczego te trzy linie zachowują się tak, a nie inaczej.

const: domyślny wybór

const tworzy wiązanie, którego nie można ponownie przypisać. Gdy napiszesz const x = 5, nie możesz później napisać x = 6, bo silnik rzuci TypeError.

To cała zasada. Ponieważ większości zmiennych w dobrze napisanym programie nie trzeba przypisywać ponownie, const pasuje do zdecydowanej większości przypadków. Gdy domyślnie sięgasz po const, miejsca, w których wartość faktycznie się zmienia, od razu rzucają się w oczy.

Częste źródło nieporozumień: const chroni wiązanie, a nie wartość. Jeśli wartością jest obiekt lub tablica, jej zawartość nadal można zmieniać:

const oznacza „ta nazwa zawsze wskazuje na ten obiekt”. Nie oznacza „ten obiekt nigdy się nie zmieni”. Jeśli sam obiekt ma być zamrożony, służy do tego Object.freeze(user), choć w praktyce większość kodu po prostu opiera się na konwencji, że obiektów const się nie modyfikuje.

let: gdy naprawdę musisz przypisać ponownie

let pod każdym względem jest taki sam jak const, poza tym, że można go ponownie przypisać. Używaj go do liczników, akumulatorów, zmiennych pętli i wszędzie tam, gdzie wartość faktycznie zmienia się w czasie.

Jeśli piszesz let i nigdy nie przypisujesz zmiennej ponownie, zmień ją na const. W większości projektów linter sam ci to podpowie.

Zakres blokowy

Zarówno let, jak i const mają zakres blokowy. Blok to wszystko między { a }: ciało if, for, funkcji, a nawet samodzielny blok { ... }. Zmienna zadeklarowana w bloku nie istnieje poza nim.

Właśnie tego chcesz. Zmienne pozostają przypisane do zadania, do którego należą, a przypadkowe kolizje nazw stają się niemożliwe.

var tak nie działa i to główny powód, by go unikać.

var: zakres funkcyjny i niespodzianki

var ma zakres najbliższej funkcji, a nie najbliższego bloku. Oznacza to, że var zadeklarowany w if lub for wycieka do otaczającej funkcji:

Ten luźny zakres jest źródłem długiej listy klasycznych błędów w JavaScript. Najsłynniejszy to pętle, w których każda iteracja współdzieli to samo var i, a wszystkie callbacki widzą na koniec ostatnią wartość.

var pozwala też bez protestu ponownie zadeklarować tę samą nazwę w tym samym zakresie, co ukrywa literówki:

Nowoczesny kod używa niemal wyłącznie let i const. var pojawia się w starszych projektach, dawnych odpowiedziach na Stack Overflow i skryptach, które muszą działać w bardzo starych środowiskach.

Hoisting i temporal dead zone

Wszystkie trzy deklaracje podlegają hoistingowi: silnik wie o nich, zanim uruchomi kod w bloku. Różnią się jednak zachowaniem przed wykonaniem linii z deklaracją.

var jest hoistowany i inicjalizowany wartością undefined. Możesz się do niego odwołać przed linią z var bez błędu:

let i const są hoistowane, ale nie są inicjalizowane. Dotknięcie ich przed deklaracją rzuca błąd. Ten przedział między wejściem do zakresu a wykonaniem deklaracji nazywa się temporal dead zone (TDZ):

TDZ to funkcja, a nie błąd. Zamienia „użyte przed deklaracją” z cichego undefined w głośny błąd, który wyłapuje mnóstwo literówek i pomyłek w kolejności.

const jako zmienna pętli for...of

Mały, ale częsty przypadek: pętle for...of tworzą świeże wiązanie w każdej iteracji, więc możesz użyć const dla zmiennej pętli, mimo że „zmienia się” ona między iteracjami.

Każda iteracja dostaje własne wiązanie name, więc żadna pojedyncza zmienna nie jest ponownie przypisywana. Klasyczne for (let i = 0; i < n; i++) nadal wymaga let, bo i to jedno wiązanie, które jest zwiększane.

Praktyczna zasada

Wybieraj deklaracje w tej kolejności:

  • const domyślnie. Jeśli wartość nie będzie ponownie przypisywana, pokaż to.
  • let, gdy wiązanie naprawdę musi się zmieniać.
  • var tylko w projekcie, który tego wymaga.

Stosowana konsekwentnie, ta zasada sprawia, że intencja każdej zmiennej jest oczywista na pierwszy rzut oka: czy da się ją przypisać ponownie i czy ma zakres bloku, czy funkcji.

MAX_RETRIES i users nigdy się nie zmieniają, więc const. successful rośnie, więc let. user to świeże wiązanie w każdej iteracji, więc const. Czytając od góry do dołu, widzisz, które wartości się ruszają, a które nie, bez uruchamiania kodu.

Dalej: typy proste

Skoro umiesz już deklarować zmienne, następne pytanie brzmi: jakie wartości mogą przechowywać? JavaScript ma niewielki zestaw typów prostych (liczby, stringi, wartości logiczne i kilka innych), a każdy z nich ma swoje dziwactwa. O nich jest następna strona.

Najczęściej zadawane pytania

Czym różnią się let, const i var w JavaScript?

const i let mają zakres blokowy i zostały dodane w ES2015. var ma zakres funkcyjny i jest starszy. Wiązań const nie można ponownie przypisać, a let można. var jest też hoistowany i inicjalizowany wartością undefined, a let i const są hoistowane, ale nie da się ich użyć, dopóki nie wykona się ich deklaracja (temporal dead zone).

Czy const sprawia, że wartość jest niezmienna w JavaScript?

Nie. const blokuje tylko ponowne przypisanie wiązania. Jeśli wartością jest obiekt lub tablica, nadal możesz zmieniać ich zawartość: const user = {}; user.name = 'Ada' działa bez problemu. Jeśli potrzebujesz prawdziwej niezmienności, sięgnij po Object.freeze albo bibliotekę.

Czy w nowoczesnym JavaScript nadal warto używać var?

Prawie nigdy. let i const mają czytelniejsze zasady zakresu i wyłapują więcej błędów już podczas parsowania. var spotkasz głównie w starszych projektach i w skryptach, które muszą działać w środowiskach bez obsługi ES2015.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ