Co to jest hoisting w javascript?



Każdy junior front-end developer powinien wiedzieć, czym jest hoisting. Zagadnienie to można dosyć łatwo zrozumieć, więc jeśli ktoś jeszcze o nim nie słyszał, może szybko nadrobić zaległości:

Co to jest hoisting?

Hoisting polega na wynoszeniu deklaracji zmiennych i funkcji „na górę” kodu (konkretnie na początek funkcji lub do zakresu zmiennych globalnych, w zależności od tego, gdzie dana zmienna lub funkcja została zadeklarowana). Oznacza to, że można odwołać się do zmiennej lub funkcji zanim jeszcze zostanie zadeklarowana.

Zobaczymy to najpierw na przykładzie zmiennnych:

Wynoszenie zmiennych

ES5 – var

Trzeba rozróżnić tu dwie rzeczy – deklarację i inicjalizację zmiennej. Deklaracja to zdefiniowanie zmiennej, a inicjalizacja to przypisanie jej wartości. Można zrobić te dwie rzeczy „jednorazowo” lub osobno:

function example() {
    var foo;                            // deklaracja zmiennej
    foo = "nowa wartosc zmiennej foo";  // inicjalizacja zmiennej

    var boo = "od razu przypisujemy wartosc"    // deklaracja i inicjalizacja
}


Pamiętać trzeba, że wynoszona jest tylko deklaracja zmiennej. Zatem, jeśli odwołamy się do zmniennej przed jej zdefiniowaniem, w odpowiedzi otrzymamy ‚undefined’:

function example() {
    console.log(foo);   // undefined
    var foo = 10;
    console.log(foo);   // 10
}

Dzieje się tak dlatego, że zmienna jest zadeklarowana, ale nie jest zdefiniowana jej wartość. Wartość odczytać możemy dopiero po inicjalizacji zmiennej, czyli poniżej var foo = 10;



ES6 – let i const

W przypadku użycia let i const zmienne nie są wynoszone na górę zakresu funkcji, ani do środowiska globalnego. Ogranicza to błędy, jakie mogłyby wyniknąć z nadpisania nazw zmiennych.

Miejsce pomiędzy deklaracją zmiennej a początkiem jej zakresu nazywa się Temporal Dead Zone (TDZ). Oznacza to, że jeśli odwołamy się do zmiennej przed jej zadeklarowaniem, otrzymamy error: ReferenceError: Cannot access ‚foo’ before initialization.

function example() {
    // Temporal Dead Zone
    console.log(foo);    // ReferenceError: Cannot access 'foo' before initialization

    let foo = 10;
    console.log(foo);    // 10
}

Zmienną możemy odczytać dopiero po jej zadeklarowaniu.



Wynoszenie funkcji

Function declaration // Deklaracja funkcji

Hoisting dotyczy również funkcji, zapisanej przy użyciu deklaracji funkcji. Tak jak przy zmiennych, oznacza to, że możemy odwołać się do funkcji zanim zostanie ona zadeklarowana:

foo();

function foo() {
    console.log('It works!');    // It works!
}


Function expression // Wyrażenie funkcji

W przypadku wyrażeń funkcji zasady dotyczące hoistinu są podobne jak w w przypadku zmiennych, tzn, jeśli przypiszemy funkcję do zmiennej var, deklaracja funkcji zostanie wyniesiona na górę zakresu zmiennej, ale ponieważ wynoszona jest tylko deklaracja, i tak nie użyjemy funkcji przed zadeklarowaniem:

foo();            // TypeError: foo is not a function

var foo = function() {
    console.log('It works!');
}

W przypadku let i const natomiast tworzy się martwa strefa (TDZ) i chcąc odwołać się do funkcji przed inicjalizacją otrzymujemy error:

foo();           // ReferenceError: Cannot access 'foo' before initialization

let foo = function() {
    console.log('It works!');
}


Z hoistingiem trzeba uważać, może się bowiem zdarzyć, że niechący nadpiszemy jakąś zmienną, do której myślimy, że nie mamy dostępu, bo przecież została zadeklarowana dopiero kilka linijek kodu niżej. Z tego względu w większości przypadków bezpieczniej jest używać let i const zamiast var.

Joanna

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *