Computer Keyboard - Głównie JavaScript

Głównie JavaScript

by Jakub T. Jankiewicz

Zakres blokowy w JavaScript

Grafika ze słowem kluczowe let oraz const

Ponieważ wpis o funkcjach w JavaScript na moim blogu ma wysoką pozycje w Google, a opisuje jeden z celi korzystania z IIFE, czyli natychmiastowo-wywoływanych wyrażeń funkcyjnych w celu tworzenia zakresu zmiennych. Postanowiłem opisać krótko jak działa const oraz let, czyli zakres blokowy w JavaScript w wersji ES6 (czyli poprawnie ES2015).

Do tej pory (przed ES6) aby dodać nowy zakres zmiennych należało stosować funkcje anonimowe czyli IIFE. Z powodu tego, że blok nie tworzył nowej zmiennej, mieliśmy taki kod, który nawiasem mówiąc, może pojawić się na rozmowie kwalifikacyjnej na stanowisko Front-End developera. (więcej pytań we wpisie 5 pytań na rozmowę kwalifikacyjną z języka JavaScript).

for (var i = 0; i <= 9; i++) {
    setTimeout(function() {
        console.log(i);
    }, i*1000);
}
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10
// ==> 10

Jest to spowodowane tym, że var wewnątrz for jest jeden na całą funkcje (jest jedna referencja) i po skończeniu działa pętli zawiera wartość 10.

Rozwiązaniem tego problemu do tej pory było tylko IIFE:

for (var i = 0; i <= 9; i++) {
    (function(i) {
        setTimeout(function() {
            console.log(i);
        }, i*1000);
    })(i);
}
// ==> 0
// ==> 1
// ==> 2
// ==> 3
// ==> 4
// ==> 5
// ==> 6
// ==> 7
// ==> 8
// ==> 9

ale wraz z wejściem ES6 (ES2015), można zmienną zadeklarować jako let, lub w przypadku pętli fo..in jako const. Zwykły for nie zadziała z const ponieważ musisz zmienić jego wartość w każdej iteracji pętli. Natomiast for..in oraz nowy for..of tworzy nową zmienną w każdej iteracji pętli.

Istnieje też możliwość deklaracji zakresu zmiennych wewnątrz pustego bloku. np.:

{
   let x = 10;
   console.log(x + 10);
}
console.log(x);

Ten kod zwróci wyjątek ReferenceError w drugiej linijce console.log, ponieważ zakres zmiennej x się skończył i jest nie zdefiniowana.

Jedna rzecz o jakiej trzeba pamiętać jest to, że nie można użyć zmiennej przed deklaracją. W przypadku var zmienną można było użyć przed jej deklaracji jeśli była umieszczona w tej samej funkcji, w tym samym zakresie zmiennej var (ang. scope) z powodu mechanizmu nazywanego z angielskiego hoisting.

console.log(x);
var x = 10;
console.log(x);

Powyższy kod nie zwróci błędu tylko wyświetli undefined oraz 10. W przypadku const oraz let.

{
   console.log(x + 10);
   let x = 10;
}

Zwrócony zostanie wyjątek ReferenceError, ponieważ zmienne let oraz const znajdują się w tzw. tymczasowej martwej strefie (ang. temporal dead zone). Podobno jest to definicja wzięta ze specyfikacji ES6 ale mi nie udało się tego potwierdzić (jest skrót TDZ w specyfikacji ale znaczy co innego).

Jeśli znasz skąd się wzięła ta nazwa napisz w komentarzu.

Różnica miedzy const a let jest taka, że do let można przypisać nową wartość. Możesz myśleć, że const jest to po prostu stała czyli zmienna, która nie może zmienić swojej wartości, ale to nie prawda.

const arr = [10];
arr.push(20);

jest to całkiem poprawny kod, który nie zmienia wartości, tylko modyfikuje obiekt, na który wskazuje zmienna. const działa jak stała referencja, której nie można zmienić. Aby uzyskać stałą należałoby użyć:

const arr = Object.freeze([10]);
arr.push(20);

ten kod zwróci wyjątek TypeError ponieważ arr jest tylko do odczytu.

źródło strony (aby zobaczyć kod na GitHubie, musisz kliknąć przycisk raw)
Komentarze

Hasło, które podasz umożliwi ponowne zalogowanie się i np. usunięcie komentarza, jest dobrowolne. Email jest szyfrowany i używany do wysyłania powiadomień o odpowiedziach do komentarzy oraz do pobierania awatara dzięki usłudze Gravatar.com.