Deklaracja zmiennych w JavaScript

Język JavaScript, tak jak język PHP, jest językiem słabo typowanym. Pomimo tego, że słabe typowanie ma swoje plusy jak przykładowo mniejsze nakłady pracy programisty, ponieważ nie musi on za każdym razem podczas deklaracji zmiennej, deklarować jej typu, gdyż tym wszystkim zajmuje się za niego interpreter lub kompilator, to jednak brak jawnego zadeklarowania typu zmiennej może prowadzić do wielu nieporozumień.

Jednak tak naprawdę nie tylko słabe typowanie w przypadku JavaScript może prowadzić do kłopotów podczas pracy z tym językiem. Cała sprawa rozchodzi się również o deklarację zmiennych, ponieważ do tego celu możemy korzystać z następujących słów kluczowych: var, let oraz const. Słowo kluczowe var znane jest już od dawna, ale dwa pozostałe zostały wprowadzone do języka wraz ze standardem ES6 (ES2015). Czym się różnią?

Var

Deklaracja zmiennej przez użycie tego słowa kluczowego jest bardzo prosta i możemy zadeklarować zmienną wraz z jakąś jej wartością początkową:

var zmienna = 1;

lub nie przypisując wstępnie do niej żadnej wartości (wartością takiej zmiennej będzie wówczas undefined):

var zmienna;

Wartość takiej zmiennej możemy również zmieniać w każdym dowolnym momencie. Jednak problem z deklaracją zmiennej przez var dotyczy zasięgu takiej zmiennej. Zmienne zadeklarowane w ten sposób mają zasięg wewnątrz funkcji, a nie tylko wewnątrz klamr (znaków { oraz }), w której została zadeklarowana, np. wewnątrz pętli. Sprawdźmy to na poniższym przykładzie:

function deklaracjaVar() {
    for (i = 1; i <= 3; i++) {
        var zmienna = `Obrót ${i}`;

        console.log('W pętli:', zmienna);
    }

    console.log('Poza pętlą:', zmienna);
}

Widać tutaj zmienną zadeklarowaną wewnątrz pętli for, a jako jej wartość jest przypisywana wartość tekstowa z informacją, który obrót pętli aktualnie się wykonuje. Na samym końcu, już poza pętlą, wypisana zostanie wartość zmiennej, która została zadeklarowana wewnątrz pętli. Oto co ujrzymy w konsoli jako wynik działania tej funkcji:

W pętli: Obrót 1
W pętli: Obrót 2
W pętli: Obrót 3
Poza pętlą: Obrót 3

W tym przykładzie zasięg zmiennej zadeklarowanej przez słowo kluczowe var jest bardzo dobrze widoczne. Pomimo tego, że zmienna została zadeklarowana wewnątrz pętli, to jednak jej ostatnią wartość możemy bez problemu odczytać poza pętlą, czyli poza klamrami, pomiędzy którymi została ona zadeklarowana.

Dlaczego coś takiego ma miejsce? Zmienna została zadeklarowana jako zmienna o zasięgu w całej funkcji więc jeszcze zanim kod został wykonany, zmienna została zadeklarowana na samym początku funkcji, a później jej wartość była modyfikowana z każdym obrotem pętli. W rzeczywistości powyższy kod działa jak ten poniższy:

function deklaracjaVar() {
    var zmienna;

    for (i = 1; i <= 3; i++) {
        zmienna = `Obrót ${i}`;

        console.log('W pętli:', zmienna);
    }

    console.log('Poza pętlą:', zmienna);
}

Jeśli nie będziemy znali tej zasady działania deklaracji zmiennej przy użyciu słowa kluczowego var, w naszym kodzie może przypadkowo znaleźć się błąd, który spowoduje nieprawidłowe działanie całego skryptu. Muszą o tym pamiętać przede wszystkim osoby, które mają już doświadczenie w pracy z innymi językami, a powyższe działanie może być dla nich zaskoczeniem.

Tak więc co zamiast deklarowania zmiennej przy pomocy var?

Let

Jeśli mamy tylko możliwość skorzystania ze standardu ES6 to właśnie słowo kluczowe let będzie bardzo dobrym wyjściem, ponieważ poprzez jego zastosowanie, zmienna zostaje zadeklarowana w tym miejscu, w którym byśmy tego chcieli, czyli pomiędzy klamrami i nie jest dostępna poza nimi. Dodatkowo również w przypadku let sprawa jest prosta i zmienna może zostać zadeklarowana z jakąś wartością:

let zmienna = 1;

lub bez wartości (undefined):

let zmienna;

Oczywiście tutaj również wartość takiej zmiennej może zostać dowolnie z czasem modyfikowana.

Zobaczmy teraz, jak wygląda zasięg zmiennej zadeklarowanej przy użyciu słowa let, poprzez lekką modyfikację poprzedniej funkcji z przykładu deklarowania zmiennej przy użyciu var:

function deklaracjaLet() {
    for (i = 1; i <= 3; i++) {
        let zmienna = `Obrót ${i}`;

        console.log('W pętli:', zmienna);
    }

    console.log('Poza pętlą:', zmienna);
}

Zasada działania tej funkcji jest dokładnie taka sama jak poprzedniej, ale wynik jej działania będzie trochę inny:

W pętli: Obrót 1
W pętli: Obrót 2
W pętli: Obrót 3
Uncaught ReferenceError: zmienna is not defined

Przykład ten dokładnie pokazuje, że zasięg zmiennej jest w tym momencie ograniczony klamrami pętli for i nie możemy odczytać jej wartości poza pętlą, o czym informuje nas wystąpienie błędu o tym, że zmienna, której wartość chcemy wyświetlić, nie została zadeklarowana.

Słowo kluczowe let może nam rozjaśnić napisany kod, jak również pozwoli na uniknięcie problemów z niepożądaną wartością zmiennej, która może zdarzyć się w przypadku deklarowania zmiennej przy użyciu słowa kluczowego var.

Const

Jest to kolejne słowo kluczowe, które pojawiło się wraz ze standardem ES6 i również służy do deklarowania zmiennych, których zasięg ograniczony jest klamrami tak jak w przypadku let (tego już nie musimy wyjaśniać), ale różnica między tymi słowami jest taka, że w przypadku const wartości zmiennej nie możemy już zmienić, ale również deklaracja zmiennej musi nastąpić z przypisywaniem do niej jakiejś wartości:

const zmienna = 1;

Deklaracja zmiennej bez przypisanej wartości:

const zmienna;

spowoduje wystąpienie błędu:

Uncaught SyntaxError: Missing initializer in const declaration

W związku z tym, że demonstracja działania zasięgu deklaracji zmiennej przy użyciu słowa const nie miałaby sensu ze względu na to, że polegałby on na przepisaniu przykładu z let i podmianie słowa kluczowego i wynik byłby dokładnie taki sam, skupmy się więc na pokazaniu co się stanie w przypadku, kiedy będziemy chcieli zmienić wartość takiej zmiennej:

function deklaracjaConst() {
    const zmienna = 'początkowa wartość';

    for (i = 1; i <= 3; i++) {
        zmienna = `Obrót ${i}`;
    }
}

W powyższym przykładzie deklarujemy zmienną (oczywiście najpierw przypisujemy do niej wartość początkową), a w pętli próbujemy wartość tej zmiennej zastąpić inną wartością. Wiemy już, że nie możemy tego zrobić, ale na dowód podam treść błędu, który zostanie nam zwrócony po wykonaniu powyższego kodu:

Uncaught TypeError: Assignment to constant variable.

Podsumowanie

Moim zdaniem, jeśli tylko mamy możliwość pisania swojego kodu w standardzie ES6, to deklarowanie zmiennych przy użyciu słowa kluczowego var nie powinno mieć miejsca z powodu potencjalnych problemów, które mogłyby pojawić się w naszym kodzie. W przypadku tego słowa kluczowego moglibyśmy spotkać się z nieprawidłowym wynikiem działania którejś z funkcji naszego skryptu, ponieważ któraś z naszych zmiennych mogłaby posiadać inną wartość, niż byśmy tego oczekiwali.

Deklarowanie zmiennych przy pomocy let oraz const pozwoli też na lepsze zrozumienie pisanego przez nas kodu przez pozostałych członków zespołu pracującego nad większym projektem lub po prostu będzie nam lepiej zrozumieć napisany tak kod, kiedy wrócimy do niego po dłuższym czasie.