Ten wpis jest kontynuacją serii wpisów, w której odpowiadam na pytania rekrutacyjne na stanowisko web developera. Jeśli nie czytałeś poprzednich wpisów z tego cyklu to koniecznie nadrób zaległości:
- Web developer – pytania rekrutacyjne cz. 1
- Web developer – pytania rekrutacyjne cz. 2
- Web developer – pytania rekrutacyjne cz. 3
- Web developer – pytania rekrutacyjne cz. 5
- Web developer – pytania rekrutacyjne – React
- Web developer – pytania rekrutacyjne – TypeScript
- Web developer – pytania rekrutacyjne – Git
- Web developer – pytania rekrutacyjne – Docker
Tym razem zwiększamy nieco tempo i pojawi się aż 15 pytań rekrutacyjnych! Standardowo – pytania pochodzą z serwisu fefaq.pl.
1. Jakie znasz frameworki do testów jednostkowych?
Najpopularniejsze środowiska testowe dla JavaScriptu, za pomocą których możemy tworzyć testy jednostkowe to:
- Mocha (dobrze się sprawdza z bibliotekami jak chai (asercje), sinon (stuby i mocki) czy Istanbul (code coverage))
- Jasmine
- Jest
- QUnit
2. Jak zrobić, aby kliknięcie labelki checkboxa powodowało zaznaczenie tego checkboxa?
Możemy to zrobić poprzez nadanie id na checkboxa oraz nadanie atrybutu for dla labelki, którego wartość będzie identyczna z id checkboxa. Przykład poniżej:
<label for="agreement"">I agree</label">
<input type="checkbox" id="agreement">
3. Czym się różni display: inline, inline-block, block?
Display inline sprawia, że elementy nie zajmują całej szerokości elementu w którym się znajdują, a jedynie tyle ile same potrzebują. Przykładem takiego zachowania są znaczniki span lub a, które domyślnie są znacznikami inline. Ustawiając dwa takie znaczniki obok siebie ich zawartość będzie się znajdować jeden za drugim. Zupełnie inaczej sprawa będzie wyglądać w przypadku znacznika p, który domyślnie jest znacznikiem typu block, czyli nawet, jeśli składa się tylko z jednego znaku, to i tak zajmie maksymalną szerokość na jaką mu pozwolimy. Oprócz tego w przypadku display inline nie mamy możliwości ustawienia górnego i dolnego marginesu oraz właściwości width i height.
Display inline-block jest swojego rodzaju kompromisem między tymi rozwiązaniami. Dostajemy tu dostęp do właściwości width, height oraz marginesów, ale elementy wciąż zachowują swój inline’owy charakter. Element zajmie tylko tyle szerokości ile potrzebuje. Jeśli nie rozumiesz jeszcze do końca różnicy, to skorzystaj z poniższego przykładu i modyfikując display zobacz jak zmieni się wygląd elementów:
<div>foo</div>
<div>bar</div>
div {
display: inline-block;
padding: 100px;
background-color: red;
margin: 10px;
width: 50px;
height: 50px;
}
4. Czym są encje w HTML?
Jeśli potrzebujemy wstawić w nasz tekst na stronie jakiś znak specjalny lub też znak, który HTML odbiera jako element składni, to możemy skorzystać z encji. Encją możemy zapisać jako tekst na przykład nawiasy ostre, które służą do tworzenia znaczników HTML. Encję tworzy poprzez znak &, następnie nazwa encji a po niej średnik. Na przykład encja znaku copyright (©) wygląda następująco: ©.
5. Do wykonania zadanie polegające na wysłaniu Ajaxem obiektu i zapisaniu w localStorage tokena, który dostanie się w ramach odpowiedzi. W przypadku błędu wyświetlić komunikat o błędzie.
Do wykonania tego zadania możemy skorzystać na przykład z Fetch API. W naszym przypadku korzystając z fetch(), przekazujemy dwa parametry: ścieżkę, z którą będziemy się komunikować oraz obiekt, w którym przekażemy na przykład jaką metodę HTTP używamy do komunikacji oraz obiekt z danymi, który otrzymaliśmy w zadaniu. Warto zaznaczyć, że drugi parametr nie jest konieczny, jeśli chcemy skorzystać z metody GET i jedynie otrzymać jakieś dane z serwera. Alternatywnie możemy skorzystać z XMLHttpRequest lub biblioteki Axios jednak w tym przykładzie skorzystam z fetch(). Przejdźmy do rozwiązania zadania:
fetch('https://example.com/token', {
method: 'POST',
body: JSON.stringify(obj)
})
.then(response => response.json())
.then(response => {
localStorage.setItem('token', response.data.token);
})
.catch(error => console.error('An error occured:', error));
6. Jak utworzyć branch za pomocą konsoli? W jaki sposób przejdziesz z jednego brancha do drugiego za pomocą konsoli?
Nowy branch w konsoli możemy utworzyć następującym poleceniem:
git branch nazwa_brancha
Do przełączenia się na nowo utworzony branch służy komenda:
git checkout nazwa_brancha
Jeśli chcemy jednocześnie utworzyć branch i przełączyć się na niego możemy skorzystać z:
git checkout -b nazwa_brancha
7. Co to jest pure function?
Aby funkcję można było nazwać pure function musi ona spełniać dwa wymagania:
- Dla takiego samego zestawu danych wejściowych musi zawsze zwracać taki sam wynik,
- Pure function nie może modyfikować zewnętrznych wartości (np. zmiennych poza swoim zakresem).
Poniżej przedstawiam kod z przykładami funkcji pure i impure:
let a = 2;
//Pure function - zawsze zwraca taki sam wynik dla danego zestawu danych i nie modyfikuje zmiennych spoza funkcji
function add(a,b) {
return a + b;
}
//Impure function - modyfikuje zmienną spoza swojego zakresu
function increment() {
return a++;
}
//Impure function - dla takich samych danych wejściowych wynik za każdym razem będzie inny
function random(a) {
return Math.random()*a;
}
console.log(add(2,4));
increment();
console.log(a)
console.log(random(3));
8. Czym są atrybuty data i gdzie możemy ich używać?
Atrybuty data możemy dodawać do znaczników HTML’a, aby przypisywać do nich jakieś dodatkowe dane. Dobrym przykładem będzie przypadek, gdy chcemy pokazać na stronie rekordy z bazy danych. Każdy rekord możemy wyświetlić w osobnym znaczniku a do znacznika dodać atrybut wraz z id tego rekordu. Atrybuty data dodajemy w postaci data-nazwa_atrybutu.
Atrybuty data możemy wykorzystać zarówno z poziomu JavaScriptu jak i z poziomu CSSa:
<div class=”record” data-id=”54759eb3c090d83494e2d804”>foo</div>
const record = document.querySelector(‘.record’);
record.dataset.id // "54759eb3c090d83494e2d804"
.record[data-id='54759eb3c090d83494e2d804'] {
color: red;
}
9. Czym się różni function declaration od function expression?
Function declaration zostaje załadowane zanim kod zostanie wykonany, natomiast function expression zostaje załadowane dopiero w momencie, gdy interpreter napotka je w kodzie. Co warto zauważyć wywołanie function expression przed jego faktycznym wystąpieniem w kodzie będzie skutkować błędem, ponieważ albo zmienna uległa hoistingowi (o którym pisałem w poprzednim artykule z tej serii) lub też w przypadku let i const taka zmienna nie została jeszcze powołana do życia. Przeanalizujmy przykład:
console.log(add(2,4));
console.log(random(3));
//Function expression
var add = function(a,b) {
return a + b;
}
//Function declaration
function random(a) {
return Math.random()*a;
}
W obecnym stanie nasz kod wyrzuci nam błąd. Przenosząc wywołanie funkcji pod function expression nasz kod zacznie działać poprawnie.
10. Czym się różni atrybut od właściwości (property) węzła HTML?
Tworząc szablon HTML i dodając znaczniki nadajemy im atrybuty. Plik HTML jest ładowany przez przeglądarkę i na jego podstawie tworzone jest drzewo DOM. Każdy element drzewa DOM posiada natomiast już właściwości, czyli properties. Za pomocą metod takich jak chociażby getElementById() możemy uzyskać dostęp do właściwości węzła (w tym przypadku elementu), których liczba jest naprawdę imponująca – najlepiej będzie przekonać się samemu – spróbuj stworzyć element na stronie, a następnie za pomocą console.log(document.getElementById(‘id_elementu’)) wyświetlić listę jego właściwości.
11. Wyjaśnij jakie elementy zostaną zawarte w następujących selektorach CSS: div, p div p div > p div + p div ~ p.
- div, p – style zostaną nałożone na znaczniki div oraz na znaczniki p.
- div p – style otrzymają znaczniki p znajdujące się w znaczniku div.
- div > p – zawiera wszystkie elementy p, których rodzicem jest znacznik div.
- div + p – obejmuje wszystkie elementy p, które są umieszczone bezpośrednio za znacznikiem div.
- div ~ p – styl otrzymają wszystkie elementy p, przed którymi wystąpił znacznik div (w obrębie jednego rodzica – wystąpienie nie jest przechodzi w dół drzewa DOM).
12. Czym są localStorage, sessionStorage oraz cookies i czym się różnią?
Wszystkie te trzy mechanizmy pozwalają nam na przechowywanie drobnych porcji danych w przeglądarce w celu ich późniejszego użycie. Do takich danych można zaliczyć wszelkiego rodzaju id, tokeny, konfiguracje etc.
Podstawową różnicą między localStorage i sessionStorage a cookiesami jest to, że cookies możemy odczytać z poziomu serwera (na przykład w PHP odbywa się to poprzez tablicę superglobalną $_COOKIE). LocalStorage i sessionStorage jesteśmy odczytać tylko z poziomu klienta.
Kolejną różnicą jest to, że cookie ma ograniczony czas życia. Możemy ustawić na przykład, aby czas życia ciasteczka wynosił 1 dzień lub 1 godzinę. Inaczej sprawa wygląda przy localStorage i sessionStorage – w przypadku pierwszego z nich dane możemy usunąć poprzez odpowiednie polecenie w kodzie JavaScript lub wyczyszczenie danych ręcznie. SessionStorage natomiast traci dane po zakończeniu sesji strony.
Różnica jest też w maksymalnych rozmiarach. Cookies oferują maksymalnie 4KB (niektóre przeglądarki oferują więcej), natomiast sessionStorage i localStorage mają w zależności od systemu, urządzenia i przeglądarki różne pojemności. Według moich źródeł najwięcej oferują Chrome oraz Firefox – 10MB.
13. Jakie znasz rodzaje pętli?
- for – jedna z pętli występujących w większości języków programowania. Jej zasada jest oparta na stworzeniu iteratora, zdefiniowaniu warunku przerwania pętli oraz modyfikacji iteratora z każdą iteracją.
- while – również klasyczna pętla. Pętla ta wykonuje kolejne iteracje dopóki warunek w niej zawarty jest prawdziwy.
- do…while – kolejna klasyczna pętla. Zasada działania tej pętli jest identyczna z działaniem pętli while, natomiast tym, co ją odróżnia jest to, że ta pętla najpierw wykonuje kod, a dopiero potem sprawdza warunek.
- for…in – pętla ta pozwala nam na iterowanie po properties (właściwościach) obiektu.
- for…of – dzięki tej pętli możemy iterować po wartościach w typach danych, które umożliwiają iterowanie (np. Array, String, Map czy Set).
14. Jakie znasz sposoby optymalizacji wydajności stron internetowych?
Temat optymalizacji stron to tak naprawdę temat rzeka – sposobów na optymalizację wydajności strony jest całe mnóstwo. Przedstawię Ci teraz techniki z których sam korzystam w swojej codziennej pracy:
- Kompresja zdjęć zamieszczanych na stronie (na przykład za pomocą narzędzia online przedstawionego w tym wpisie),
- Kompresja plików audio i video,
- Korzystanie z CDN’ów zamiast zwiększania liczby plików na naszym serwerze (oprócz zwiększenia wydajności oszczędzamy też miejsce 😉 ),
- Optymalizacja na poziomie kodu – usunięcie zbędnego i nieużywanego kodu, refaktoryzacja i optymalizacja używanego kodu,
- Minifikacja i obfuskacja kodu,
- Ładowanie skryptów przed zamknięciem body,
- Umiejętne cache’owanie zasobów.
Samych technik optymalizacji wydajności jest znacznie więcej, natomiast podałem tu te, które są moim must have. Bardzo zachęcam do podzielenia się w komentarzach innymi technikami do zwiększania wydajności! Zachęcam też do zapoznania się z artykułem ze źródeł, gdzie jest podane sporo więcej technik optymalizacji.
15. Napisz funkcję, która będzie wywoływać się co 0,5 sekundy. Funkcja powinna wywołać się nie więcej niż 4 razy. Dodatkowo powinna mieć opcję natychmiastowego zatrzymania.
function example() {
let a = 4;
const interval = setInterval(function() {
console.log(a--);
if(!a) clearInterval(interval);
}, 500);
}
example();
Do napisania tej funkcji wykorzystałem funkcję setInterval(), która umożliwia na wywoływanie akcji w danym okresie czasowym (w naszym przypadku 0,5 sekundy). Dodatkowo po 4 użyciu przerywamy nasz interwał za pomocją clearInterval().
Podsumowanie
Jak zwykle zachęcam do pozostawiania ocen i komentarzy. Jesli znasz jakieś ciekawe pytania, które mogłyby pojawić się w tej serii to również możesz zadać je w komentarzu. Polecam również zapoznać się ze źródłami i materiałami dodatkowymi, gdzie niektóre tematy zostały rozwinięte znacznie bardziej, jak chociażby temat optymalizacji stron internetowych.
Źródła i materiały dodatkowe:
- https://www.nafrontendzie.pl/3-najpopularniejsze-frameworki-testowanie-javascript
- https://www.youtube.com/watch?v=g6oEpkbhoeQ
- https://stackoverflow.com/questions/9189810/css-display-inline-vs-inline-block
- https://dev.w3.org/html5/html-author/charref
- https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
- https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches
- https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976
- https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
- https://stackoverflow.com/questions/1013385/what-is-the-difference-between-a-function-expression-vs-declaration-in-javascrip
- https://youtu.be/AOSYY1_np_4
- https://gomakethings.com/function-expressions-vs-function-declarations
- https://stackoverflow.com/questions/6003819/what-is-the-difference-between-properties-and-attributes-in-html
- https://stackoverflow.com/questions/8894243/why-cookies-dont-expire-after-closing-browser
- https://stackoverflow.com/questions/640938/what-is-the-maximum-size-of-a-web-browsers-cookies-key
- https://flaviocopes.com/web-storage-api/#desktop
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for…of
- https://piecioshka.pl/blog/2018/12/10/pytanie-rekrutacyjne-nr-2-javascript-developer.html
w pkt. 15. rozwiązaniu brakuje opcji natychmiastowego zatrzymania.Osobiście chyba dałbym, aby funkcja
example()
zwracała wartośćinterval
, aby można było wykonać:const inteval = example()
// clearInterval(interval)