Pytania rekrutacyjne dla Front-end developerów
-
Główna różnica polega na wiązaniu
this:- Funkcje strzałkowe nie mają własnego
this– dziedziczą je z otaczającego zakresu. - Zwykłe funkcje mają własne
this, które zależy od sposobu ich wywołania.
const person = { name: "Alice", sayHello: function() { console.log("Hello, my name is " + this.name); }, sayHelloArrow: () => { console.log("Hello, my name is " + this.name); } }; person.sayHello(); // "Hello, my name is Alice" person.sayHelloArrow(); // "Hello, my name is undefined" (bo `this` odnosi się do otoczenia globalnego)Ponadto funkcja strzałkowa:
- Nie posiada:
super,argumensinew.target. Te wartości definiowane są przez najbliższą funkcję niestrzałkową. - Nie może zostać wywołana za pomocą
new, bo nie posiada metody construct, więc nie może być konstruktorem. - Nie posiada właściwości
prototype
- Funkcje strzałkowe nie mają własnego
-
Promise to obiekt w Javascript, który reprezentuje zakończenie (sukces lub porażkę) asynchronicznej operacji i jej wartości. Ponieważ wykonanie niektórych części kodu może zająć trochę więcej czasu, a odpowiedź oczekiwana jest natychmiast (by silnik javascript mógł przejść do wykonania kolejnych części kodu z kolejki), kiedy nie ma jeszcze wyniku, z którym można dalej pracować, zwracana jest obietnica otrzymania tego wyniku. Można wtedy określić, co zrobić z otrzymanym wynikiem w przypadku sukcesu (gdy kod zostanie prawidłowo przetworzony) lub porażki (kiedy kodu nie uda się przetworzyć).
const promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Data loaded"), 2000); }); promise.then(console.log).catch(console.error); -
Zwykła tablica indeksowana jest za pomocą liczb (zaczynając od 0), pod każdym kolejnym indeksem zapisane są jakieś dane:
arr[5, 4, 3, 2, 1]; arr(0) = 5;Tablica asocjacyjna zamiast liczb wykorzystuje ciągi znaków. Działa na zasadzie klucz-wartość. W JavaScript tablice nie są asocjacyjne – klucze muszą być liczbami. Do przechowywania par klucz-wartość używa się obiektów:
const obj = { name: "John", age: 30 }; -
Podwójny znak równości porównuje dane bez względu na ich typ, a potrójny znak równości porównuje jeszcze dodatkowo zgodność typów.
console.log(1 == '1'); // true console.log(1 === '1'); // false console.log(0 == false); // true console.log(0 === false); // false -
var – posiada zakres funkcyjny i podlega hoistingowi. Onacza to, że zadeklarowanie zmiennej var w którymkolwiek miejscu funkcji umożliwia odwołanie się do niej, ponieważ jej deklaracja jest wynoszona na początek zakresu funkcji. Ogranicza ją więc zakres funkcji.
let, const – mają zakres blokowy. Oznacza to, że jeśli zmienna zadeklarowana przy użyciu
letlubconstużyta zostanie w blokuif {}, to poza tym blokiem będzie niedostępna (w przeciwieństwie dovar). Ograniczone są zakresem najbliższego bloku, zdefiniowanego przez nawiasy{}. Ponadto ich deklaracja nie podlega hoistingowi, co oznacza, że nie można się do nich odwołać przed ich zadeklarowaniem (powstaje wtedy TZD – temporal dead zone).Zmienna stworzona przy użyciu
letnie musi posiadać przypisanej wartości, bo możną ją później zmienić (np.let foo;).Stała stworzona przy użyciu
constmusi od razu posiadać przypisaną wartość (cost foo = "something"), bo nie można jej zmienić (choć można zmodyfikować jej wartość, jeśli jest obiaktem, tablicą – ponieważ const zapobiega zmianie bindowania, czyli zmianie typu wartości, a nie samej wartości).const boo = ["gruszka", "jablko"]; boo.push("malina"); console.log(boo) // "gruszka", "jablko", "malina" -
Funkcja callback to funkcja przekazana jako parametr innej funkcji. Dzięki takiemu podejściu, możliwe jest wskazanie działania, które ma nastąpić, w zależności od wyników działania poprzedniej funkcji. Innymi słowy, jest to funkcja, która ma zostać wykonana po zakończeniu wykonywania innej funkcji:
function greet(url, callback) { console.log("Sending request to:", url); setTimeout(() => { const response = "Hello from API!"; callback(response); // Call the callback function with the response }, 2000); } // Calling greet with a URL and an anonymous callback function greet("https://api.example.com", function(response) { console.log("Response received:", response); });W powyższym przykładzie funkcja greet(), wykona jakąć akcję, np. wyśle zapytanie pod wskazany adres URL, a odpowiedź zostanie przekierowana do funkcji anonimowej (callback). W ten sposób, dopiero gdy nadejdzie odpowiedź z zewnętrznego API, dane zostaną wyświetlone w konsoli.
Bardzo często, aby sprostać wymaganiom biznesowym, będziemy potrzebowali wielokrotnego zagnieżdżania wywołań zwrotnych. Powstały w ten sposób kod jest trudny w utrzymaniu i mało czytelny. Często zdarza się też, że kolejne funkcje zwrotne porozrzucane są w różnych miejscach kodu czy nawet w różnych plikach, co dodatkowo utrudnia pracę. Tego typu sytuację nazywamy piekłem wywołań zwrotnych (ang. callback hell).
Jak uniknąć callback hell:
- używajac obietnic
- używajac async/await
-
Funkcje anonimowe to funkcje bez nazwy, które często używa się w:
Callbackach – np. w forEach, setTimeout, addEventListener.
setTimeout(() => { // some code }, 2000);Wyrażeniach funkcyjnych – np. przypisane do zmiennej:
const hello = function (name) { return `Hi, ${name}!`; }; console.log(hello("John"));Funkcjach strzałkowych (arrow functions) – krótsza składnia dla funkcji anonimowych:
const pdouble = x => x * 2; console.log(double(5)); // 10Natychmiastowo wywoływanych funkcjach (IIFE) – wykonują się od razu po zdefiniowaniu:
(function () { console.log("it will be done immediately!"); })(); -
Domknięcie to funkcja, która zapamiętuje zakres (wartości zmiennych), w którym została utworzona, nawet jeśli jest wywoływana później, poza tym zakresem.
W JavaScript każda funkcja tworzy swój własny zakres (scope). Jeśli funkcja jest tworzona wewnątrz innej funkcji, to ma dostęp do zmiennych tej funkcji nadrzędnej, nawet po jej zakończeniu.
function outerFunction() { let count = 0; // Zmienna w zakresie funkcji nadrzędnej return function innerFunction() { count++; // Nadal ma dostęp do count console.log(count); }; } const increment = outerFunction(); // Zwrócona funkcja zapamiętuje `count` increment(); // 1 increment(); // 2 increment(); // 3innerFunctionma dostęp docount, mimo żeouterFunctionjuż się zakończyła. To właśnie jest domknięcie – funkcja przechowuje dostęp do swojego zakresu, nawet gdy funkcja nadrzędna przestaje działać. -
To tablica, która działa na zasadzie klucz-wartość, dzięki czemu odczytywanie danych jest bardzo szybkie i nie zależy od wielkości tablicy. W tablicy mieszającej stosuje się funkcję mieszającą, która dla danego klucza wyznacza indeks w tablicy. W najprostszym przypadku do każdego indeksu przypisany jest jeden klucz, co sprawia, że czas odczytywania danych jest bardzo szybki i wynosi O(1).
Sprawa komplikuje się, kiedy funkcja mieszająca przypisze ten sam indeks w tablicy dwóm kluczom. Wtedy powstaje tzw. kolizja – sytuacja, w której pod jednym indeksem znajduje się kilka kluczy. Szukając odpowiedniego klucza i przypisanej do niego wartości tablica musi przeszukać kilka elementów przypisanych do tego samego indeksu (tak jakby przeszukiwała drugą tablicę – choć niekoniecznie dane zapisane pod jednym indeksem muszą być w formie tablicy). Czas wyszukiwania danych wydłuża się w takiej sytuacji do O(n) – bo pod danym indeksem trzeba przeszukać n elementów, które są tam przypisane.
W JavaScript tablicą mieszającą jest np. obiekt lub Map
const hashtable = { "key1": "value1", "key2": "value2" }; console.log(hashtable["key1"]); // "value1" const map = new Map(); map.set(1, "one"); console.log(map.get(1)); // "one" -
- Delegacja zdarzeń – przypisywanie eventu do rodzica zamiast każdego elementu osobno.
- Propagacja zdarzeń – sposób, w jaki event przechodzi przez DOM (bubbling lub capturing).