Kilka dni temu zostałem poproszony o przygotowanie 3 pytań, dla kandydata na programistę Full Stack, do zbliżającej się rozmowy kwalifikacyjnej, z języka JavaScript. Przygotowałem 4 i potem dodałem jeszcze jedno. Oto one.
Co to są domknięcia (ang. closures)?
W skrócie, domknięcia są to funkcje, które mają dostęp do środowiska, w którym zostały zdefiniowane. Pytanie z domknięć to chyba najpopularniejsze pytanie na rozmowach rekrutacyjnych.
Popatrz na poniższy kod:
Wywołanie funkcji c()
zwróci liczbę 10, mimo że zakres dla zmiennej b się skończył, kiedy skończyła się funkcja a.
Zmienna b jest nadal jednak dostępna wewnątrz funkcji wewnętrznej, dzięki czemuś o nazwie domknięcia.
Mówiąc dokładnie domknięcie to funkcja, która ma dostęp do środowiska, w którym została zdefiniowana. Co najlepiej jest widoczne, gdy zwracamy funkcje (czyli w funkcjach wyższego rzędu).
Co to jest hoisting?
Deklaracje funkcji i zmiennych są przenoszone na początek funkcji, w której zostały zdefiniowane, ale już przypisanie nie np:
Jest konwertowane przez engine JavaScript na
Dlatego powyższe wywołanie console.log
nie zwróci wyjątku ReferenceError
, ani nie wyświetli wartości 5, tylko wypisze wartość undefined
, ponieważ zmienna bez przypisania ma właśnie wartość undefined
.
Dokładny mechanizm wygląda tak, że interpreter „przechodzi” kod dwa razy, za pierwszym „wyciągając” wszystkie deklaracje. Dlatego przy drugim przejściu są na początku bloku, ponieważ są już stworzone wewnętrzne referencje. Tak naprawdę hoisting, nie jest to coś, co znajduje się w specyfikacji ECMAScript (nigdzie nie występuje słowo hoisting), oraz zaimplementowane w silnikach JavaScript, ale wyjaśnienie działania, któremu nadano taką właśnie nazwę.
Czy taki kod wyświetli liczbę 0, jeśli nie dlaczego?
Nie zadziała, wyświetli 10, tak jak wywołanie każdej z funkcji, ponieważ w języku JavaScript zakres var
nie jest blokowy (czyli tylko dla bloku for w przykładzie) tylko funkcyjny. Każda pętla w forze ma tą samą zmienną. Dlatego na końcu jak się skończy for
, każda funkcja będzie miała referencje to tej samej zmiennej, która ma wartość 10.
Aby to naprawić wystarczy użyć let
z ES6:
albo stworzyć funkcje ze zmienną i
, czyli IIFE, który utworzy nowy scope (ang. zasięg) dla tej zmiennej, to rozwiązanie będzie bardziej przenośne między przeglądarkami:
Czy ten kod zadziała?
Nie ponieważ this
w funkcji map
będzie to obiekt window
albo zwróci wyjątek TypeError
jeśli będzie użyty "strict mode"
, aby to naprawić można użyć tzw. funkcji strzałkowej (ang. arrow function) z ES6 w map:
lub zapisać this
do zmiennej (bardziej przenośne rozwiązanie) np.:
Co wyświetli poniższy kod?
Wyświetli:
0
1
2
3
for..in
operuje na kluczach. W przypadku tablic są to indeksy, aby iterować po wartościach tablicy, można użyć normalnego fora:
Albo użyć pętli z ES6 for..of
:
można także użyć funkcji forEach
z ES5.
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.