search check home clock-o tag tags chevron-left chevron-right chevron-up chevron-down twitter facebook github rss comment comments terminal code

[JS] Jak używać let i const w kodzie JavaScript?

[JS] Jak używać let i const w kodzie JavaScript?

Wraz z nadejściem standardów ES6+ w kodzie JavaScript na dobre zagościły nowe sposoby deklaracji zmiennych. W przeszłości można było korzystać tylko z var. Lecz już od jakiegoś czasu nic nie stoi na przeszkodzie, aby korzystać z nowocześniejszych rozwiązań.

Za pomocą let i const możesz deklarować zmienne podobnie jak za pomocą var. Najważniejszą zmianę jaką one wprowadzają to zasięg zmiennych. W przypadku korzystania z var to występuje tzw. hoisting. Hoisting polega na tym, że wszystkie zmienne zadeklarowane za pomocą var są przenoszone w fazie kompilacji na samą górę ciała funkcji. Zobacz na przykładzie poniżej:

1
2
3
4
5
var height = 190;
 
size = size + height;
 
var size = 10;

Powyższy zapis po zinterpretowaniu przez przeglądarkę przyjmie następującą postać:

1
2
3
4
5
6
var height;
var size;
 
height = 190;
size = size + height;
size = 10;

Z tego powodu, bardzo często spotykaną praktyką jest deklarowanie zmiennych przez programistę na początku ciała funkcji. Dzięki temu w sposób jawny informujemy osobę, która czyta kod jakie zmienne są używane w kodzie. Zapobiegamy wtedy potencjalnym błędom wynikającym z ponownego zadeklarowania zmiennej czy też wynikającym z braku przejrzystości kodu, gdzie znaczniki var są porozsiewane w wielu miejscach w kodzie.

Wracając do let i const to różnica między nimi a var polega na zasięgu zmiennych. O ile var ma zasięg funkcyjny i występuje hoisting, to o tyle let i const mają zasięg blokowy. Co to oznacza?

Oznacza to, że zmienne będą dostępne w danym bloku kodu i nie będzie występował hoisting. Spójrz na przykład poniżej:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
console.log('hoisting:check', check);
 
 
const check = 4;
 
if (true) {
    let check = 2;
 
    console.log('let:check', check);
}
 
console.log('const:check:1', check);
 
check = 3;
 
console.log('const:check:2', check);

Gdy uruchomisz powyższy kod to zauważysz błąd informujący o tym, że zmienna check nie została zadeklarowana. Świadczy to o braku hoistingu. Gdy usuniesz pierwszy console.log() i ponownie uruchomisz kod, to zobaczysz dwa wywołania console.log(). Pierwszy zwróci nam informację, że zmienna check ma wartość 2, a drugi pokaże informację, że zmienna ma wartość 4.

Jest to bardzo ważna informacja, ponieważ mówi nam, że za pomocą let zmieniliśmy wartość zmiennej tylko i wyłącznie wewnątrz bloku warunku if i poza blokiem wartość zmiennej pozostaje niezmieniona.

Trzeciego wywołania console.log() nie zobaczysz, ponieważ wystąpi błąd związany z niemożliwością przypisania nowej wartości do zmiennej zadeklarowanej za pomocą const. Czy to świadczy o tym, że zmienne raz zadeklarowane za pomocą const są stałe?

Otóż nie, zmienne zadeklarowane za pomocą const nie są stałe. Stałe są referencje do zmiennych. To znaczy, nie możesz podmienić wartości w takiej zmiennej, jeśli jej wartość jest typu Boolean, String, Function czy Number, ale jest możliwość zmiany zawartości zmiennej jeśli jej wartość jest tablicą bądź obiektem. Gdy modyfikujemy tablicę czy obiekt, referencja do tej zmiennej pozostaje niezmieniona mimo zmiany zawartości tablicy/obiektu. Spójrz na przykład poniżej:

1
2
3
4
5
6
7
8
const names = [];
const person = {};
 
person.name = 'Piotr';
names.push('Nalepa');
 
console.log('names', names);
console.log('person', person);

Zadeklarowaliśmy zmienne za pomocą const i zmodyfikowaliśmy zawartość tablicy ze zmiennej names i obiektu ze zmiennej person. Taka manipulacja nie wywołała żadnego błędu w konsoli i jesteśmy w stanie zobaczyć rezultaty wywołań console.log().

Podsumowanie

Celem tego wpisu było ukazanie różnic pomiędzy var a let i const. Jestem przekonany, że po przeczytaniu tego wpisu będziesz w stanie w sposób swobodny korzystać z nowych funkcjonalności.

Na koniec dodam jeszcze, że pisząc nowy kod w większości przypadków będziesz potrzebować wyłącznie const. Deklaracja zmiennych za pomocą let występuje znacznie rzadziej, najczęściej w różnego rodzaju pętlach.

Ten wpis otwiera nową serię wpisów dotyczących najnowszych standardów JavaScript. W kolejnych odcinkach możesz się spodziewać jeszcze większej ilości informacji na temat ES6.

  • Maciej Cąderek

    „Powyższy zapis po zinterpretowaniu przez przeglądarkę przyjmie następującą postać: […]”. Bzdura, zostanie to zinterpretowane jako coś takiego:
    var height, size;
    height = 190
    size = size + height
    size = 10

  • Masz rację, wystąpiła pewna nieścisłość z mojej strony. Co nie oznacza, że rezultat końcowy będzie inny.

  • Cieszę się, że znalazłeś ten błąd.

  • Poza tym błędem, bardzo dobrze przygotowany merytorycznie wpis. Pozdrawiam

  • Proponuję również wspomnieć (szczególnie dla osób zaczynających „zabawę” z JS) o zachowaniu się deklaracji let znajdującej się wewnątrz definiowania pętli for, dzięki czemu nie musimy już tworzyć sztucznego dodatkowego zasięgu IIFE, Pozdrawiam

  • Ostatnio ciekawą rzecz zauważyłem korzystając z TSLintera (linter do TypeScript, czyli mozna powiedzieć „nadjęzyka” JavaScriptu). Jeżeli używamy pętli for z licznikiem (standardowo for (i = 0; i < length; i++) w skrócie) to deklaruje się zazwyczaj licznik jako let, natomiast jeżeli mamy pętle typu for each (for (obj : objects)) to linter domyślnie ustawiony podpowiada by zmienna była const. Dlaczego tak jest?

    Sam wpis świetny!

  • A czy ta sama informacja nie została zawarta w przykładzie z pętlą if? Tam też jest struktura blokowa kodu.

  • Szczerze mówiąc, nie pracowałem do tej pory z TS. Jeśli mógłbyś przedstawić pełny kod, to wtedy mógłbym się jakoś do tego odnieść. Na podstawie tego co do tej pory napisałeś nie jestem w stanie podać satysfakcjonującej odpowiedzi 🙂

  • TypeScript jednak tu nie ma nic do rzeczy. Mój błąd. Co do przykładu. Załóżmy że mamy tabelę:

    numbers = [1, 2, 3…]

    Jeżeli chciałbym wypisać to używając licznika, licznik jest wtedy ‚let’

    for (let i = 0; i < numbers.length; i++) console.log(numbers[i]);

    Natomiast jeżeli zrobimy for eacha, const jest ok i linter także podpowiada const

    for (const number of numbers) console.log(number);

    Pytanie moje brzmi: Jak to mozliwe ze w takim przypadku const jest ok, nie musi byc to let?

  • Jeśli dobrze rozumiem, to w przypadku licznika zmienna jest inicjalizowana raz i może ulec zmianom. Stąd jest to let.
    W przypadku konstrukcji for-of tworzona jest zmienna „stała” dla każdej iteracji. Nie chcemy zmieniać zawartości tej zmiennej stąd jest ustawiona jako const.

  • tak też myślałem, dzięki!

  • Pingback: [JS] ECMAScript 6 - jaka jest różnica między var i let? | Piotr Nalepa - Blog webmasterski | Tutoriale JavaScript, CSS i nie tylko()

  • Pingback: Wywiad z Piotrem Kowalskim – blogerem, youtuberem i organizatorem WarsawJS | Piotr Nalepa - Blog webmasterski | Tutoriale JavaScript, CSS i nie tylko()