Jedną z części rozmowy rekrutacyjnej na stanowisko Junior Web Developera jest rozmowa techniczna. Często podczas tej części rozmowy rekruter poprosi Cię o opisanie projektów, w których do tej pory brałeś(aś) udział. Warto wtedy opisać czego się nauczyłeś(aś), jakie trudności napotkałeś(aś) oraz jak udało Ci się z nimi uporać. W wielu przypadkach rekruterowi to wystarczy. Gdy jednak nie masz zbyt wiele doświadczenia, to rekruter będzie chciał sprawdzić Twoją wiedzę poprzez serię kilku pytań technicznych.
Część pytań pochodzi z portalu DevFAQ — bazy z pytaniami rekrutacyjnymi tworzonej przez społeczność. Część pytań pochodzi z mojego e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer, który możesz odebrać, zapisując się na mój mailing. Nie wszystkie pytania zawarte w tym artykule znajdziesz w moim e-booku, więc zachęcam Cię do przeczytania tego wpisu, nawet jeśli planujesz przeczytać e-booka.
Na blogu tematyce pytań technicznych poświęciłem szerszą uwagę w serii wpisów. Zachęcam do sprawdzenia pozostałych artykułów:
- Junior Web Developer – pytania rekrutacyjne cz. 1
- Junior Web Developer – pytania rekrutacyjne cz. 3
- Junior Web Developer – pytania rekrutacyjne cz. 4
- Junior Web Developer – pytania rekrutacyjne cz. 5
- Junior Web Developer – pytania rekrutacyjne – React
- Programista – pytania rekrutacyjne – TypeScript
- Programista – pytania rekrutacyjne – Git
- Programista – pytania rekrutacyjne – Docker
- Programista – pytania rekrutacyjne – bazy danych
Pytania z tej serii możesz również traktować jako trening i sprawdzenie swoich umiejętności przed rozmową rekrutacyjną.
Czym są falsy values?
Falsy values są to wartości, które przekazane do warunku klauzuli if
dadzą wynik false. Wyróżnia się następujące falsy values: false
, null
, undefined
, 0
, NaN
, pusty string.
Jak przejąć kontrolę nad prawym przyciskiem myszy?
Do przejęcia kontroli nad prawym przyciskiem myszy należy skorzystać z mechanizmu event listenerów. Event listener należy podpiąć do elementu na stronie. W momencie zaistnienia nasłuchiwanego zdarzenia wywołana zostanie wcześniej zadeklarowana akcja. Dla zdarzenia kliknięcia prawym przyciskiem myszy można wykorzystać zdarzenia mouseup
lub auxclick
. Aby móc obsłużyć zdarzenie w dowolnym miejscu na stronie, warto nasłuchiwać na element document
.
document.addEventListener('auxclick', function() {
console.log('Hello!');
});
Na czym polega referencja? Jakie typy danych są przekazywane przez referencję w JS?
Referencja to wskazanie miejsca w pamięci, w jakim znajduje się dana wartość. W JavaScript typem referencyjnym jest typ object
oraz tablice, które tak naprawdę też są typem object
. Aby lepiej przedstawić działanie referencji, przygotowałem przykład.
const hobbit1 = {
name: "Bilbo",
surname: "Baggins"
}
const hobbit2 = hobbit1;
hobbit2.name = "Frodo";
console.log(hobbit1);
console.log(hobbit2);
Uruchamiając kod, można zauważyć, że imię Frodo zostało przypisane obu hobbitom. Stało się to za sprawą referencji. Tak naprawdę zmienne hobbit1
i hobbit2
odwołują się do tego samego hobbita. Tworząc zmienną hobbit2
, została do niej przypisana referencja przechowywana w zmiennej hobbit1
.
Warte uwagi jest również zachowanie zmiennych typu referencyjnego w kontekście słowa kluczowego const
. Zmiana imienia nie powoduje zmiany referencji, a jedynie wartości, do której przechowywana jest referencja. W konsekwencji modyfikacje obiektów i tablic przypisanych do zmiennych typu const
nie powodują rzucenia błędu. Błąd zostanie rzucony dopiero w momencie, gdy programista spróbuje pozbyć się referencji z takiej zmiennej, np. próbując ją nadpisać inną wartością.
Kolejnym ciekawym zagadnieniem dotyczącym typów referencyjnych jest porównywanie ich ze sobą. Tu również przydatny będzie przykład.
const hobbit1 = {
name: "Bilbo",
surname: "Baggins"
}
const hobbit2 = {
name: "Bilbo",
surname: "Baggins"
}
console.log(hobbit1 == hobbit2);
Porównując zmienne typu referencyjnego, porównywane są nie wartości, a referencje. Mimo że hobbit1
i hobbit2
mają identyczną strukturę i wartości, to w pamięci komputera mają one inne adresy w pamięci, przez co ich referencje są różne. W konsekwencji pierwszy console.log
wskaże false
.
Więcej o pracy z typem object
możesz dowiedzieć się z artykułu Kopiowanie obiektów w JavaScript, gdzie temat został rozwinięty nieco bardziej.
Jak zastosować dziedziczenie w SCSS?
Jeśli w Twoim CV znalazła się znajomość SCSS, to prawdopodobnie w trakcie rozmowy padnie jakieś pytanie z nim związane. Do zastosowania dziedziczenia w SCSS można podejść dwojako. Pierwszy ze sposobów na dziedziczenie w SCSS to skorzystanie ze słowa kluczowego @extend
. Drugim sposobem jest wykorzystanie @mixin
. Otrzymany rezultat będzie taki sam, niezależnie od zastosowanego rozwiązania. Różnice między nimi bardzo dobrze opisuje podlinkowana dyskusja na StackOverflow. Zachęcam do zapoznania się z przykładem kodu SCSS wykorzystującym zarówno @mixin
, jak i @extend
.
@mixin btn {
padding: 15px 20px;
border: none;
outline: none;
background-color: rgb(66, 103, 178);
color: #fff;
font-weight: bold;
font-size: 20px;
}
.btn {
padding: 15px 20px;
border: none;
outline: none;
background-color: rgb(66, 103, 178);
color: #fff;
font-weight: bold;
font-size: 20px;
}
.btn-default {
@extend .btn;
}
.btn-danger {
@extend .btn;
background-color: #f00;
}
.btn-success {
@include btn;
background-color: #0f0;
}
Korzystając z okazji, warto pokazać możliwość definiowania własnych funkcji. Do stworzenia funkcji w SCSS służy słowo kluczowe @function
. Funkcje mogą być niezwykle przydatne do tworzenia np. dynamicznych wartości czy obliczeń. W poniższym przykładzie stworzyłem funkcję ustawiającą szerokość elementów z klasą .btn
na wielokrotności 150px
.
@function setWidth($number){
@return 150px * $number
}
.btn-success {
width: setWidth(2);
}
.btn-danger {
width: setWidth(1);
}
Dlaczego zazwyczaj skrypty podłączamy przed zamknięciem tagu body
?
Domyślnie podczas ładowania skryptu za pomocą tagu script
parsowanie HTML jest wstrzymane do czasu zakończenia działania skryptu. Takie działanie powoduje kilka komplikacji. Przede wszystkim opóźniamy ładowanie naszej strony. Ładując masywny skrypt, możemy spowodować, że odbiorca później zobaczy zawartość naszej witryny, co niekorzystnie wpływa na UX i SEO. Drugą komplikacją jest odwoływanie się do elementów drzewa DOM.
Dodając znaczniki script
do elementu head
, powodujemy, że body się nie zdąży załadować, przez co próba jakichkolwiek operacji na elementach DOM będzie skutkowała błędami, ponieważ elementy DOM nie zostały jeszcze stworzone. Można sobie z tym poradzić i skorzystać ze zdarzenia DOMContentLoaded
lub właśnie przenosząc tagi script
przed zamknięcie tagu body
.
Alternatywnie możemy użyć dołączenia skryptu w wariancie <script type="module">
i wstawić w sekcję head
. Skrypty typu module
nie blokują renderowania strony. Ponadto, umieszczenie go wysoko pozwala na jego szybkie załadowanie.
Wyjaśnij różnicę pomiędzy <script async>
i <script defer>
Jest to pytanie ściśle powiązane z poprzednim. Aby uporać się z problemami opisanymi w poprzednim pytaniu, można skorzystać z importowania skryptów async
lub defer
. Słowo kluczowe async
powoduje, że skrypty nie wstrzymują parsowania kodu HTML podczas ładowania. Wstrzymanie następuje jednak w momencie wykonywania skryptów. Użycie defer
również nie powoduje wstrzymania parsowania kodu HTML. Różny jest jednak moment wykonania skryptów. W tym przypadku kod wykona się dopiero po zakończeniu parsowania kodu HTML.
Co to jest chmod
?
Pytanie nie jest ściśle powiązana z web developmentem. Niemniej jednak znajomość podstawowych mechanizmów pracy z systemami Ci się przyda. W szczególności, jeśli chodzi o wykorzystanie systemów opartych o Linuxa. Wiedza ta przyda Ci się przy konfiguracji systemu, uruchamianiu usług na serwerze, czy nawet podczas uploadu plików na serwer.
Polecenie chmod
znajdziemy w systemach z rodziny Linuxa oraz na systemach na komputerach firmy Apple. Polecenie to definiuje prawa dostępowe do danego pliku bądź katalogu.
Składnia polecenia chmod wygląda następująco: chmod [liczba][liczba][liczba] nazwa_katalogu
. Każda liczba odpowiada określonemu rodzajowi uprawnień. Pierwsza z nich to uprawnienia właściciela, druga grupy, a trzecia dotyczy pozostałych użytkowników. Można również skorzystać z flagi -R
, aby nadać uprawnienia rekursywnie, czyli wraz z plikami i podkatalogami w danym katalogu. Uprawnienia można definiować następującymi liczbami:
4
– prawo do odczytu;2
– prawo do zapisu;1
– prawo do wykonania;0
– brak uprawnień.
Liczby te można sumować, tak aby przyznać więcej niż jedno uprawnienie. Każda z liczb w poleceniu odpowiada za inną segment użytkowników.
Rozważmy przykład — chcemy nadać właścicielowi katalogu www
wszystkie możliwe uprawnienia, grupie prawa do odczytu, a pozostałym użytkownikom nie chcemy nadać żadnych praw. Pliki i podkatalogi również mają mieć identyczne uprawnienia. Polecenie będzie wyglądało następująco: chmod -R 740 www
.
Czym jest REST API?
REST API to interfejs programistyczny aplikacji zgodny z zasadami architektury REST:
- odseparowanie interfejsu użytkownika od operacji na serwerze;
- serwer nie przechowuje stanu o sesji użytkownika;
- REST zakłada wykorzystanie cache. Odpowiedź, którą użytkownik otrzyma z REST API, musi jasno definiować czy ma ona być cacheable, czy non-cacheable;
- endpointy, czyli adresy zasobów, powinny jednoznacznie wskazywać, do jakiego zasobu się odwołują. Struktura REST API musi być niezależna od schematu bazy danych wykorzystywanej aplikacji;
- separacja warstw. Oznacza, że należy oddzielić warstwy dostępu do danych, logiki biznesowej oraz prezentacji;
- możliwość udostępniania skryptów wykonywalnych użytkownikom (opcjonalnie).
REST API najczęściej opiera się o protokół HTTP i operuje na formacie danych JSON. Znacznie bardziej temat REST API rozwinąłem w artykule Wprowadzenie do REST API.
Omów pokrótce, na czym polega podatność XSS
Celowo w pytaniu użyłem słowa pokrótce. O ile nie kandydujesz na stanowisko związane z cyberbezpieczeństwem, prawdopodobnie nikt nie będzie od Ciebie oczekiwał wszystkich szczegółów i niunasów związanych z wykorzystaniem znanych podatności. Warto jednak znać założenia najczęściej spotykanych podatności w Web Developmencie.
Zgodnie z definicją z OWASP podatność Cross-Site Scripting (XSS) umożliwia wykonywanie skryptów w przeglądarce ofiary, które mogą ukraść sesje ofiary, niszczyć strony internetowe lub przekierować ofiarę na złośliwe strony. Z wybranych rodzajów podatności XSS warto wymienić:
- Stored XSS – zachodzi w momencie, gdy złośliwy kod przekazany przez atakującego został zapisany w bazie danych lub innym systemie. Przy wejściu na podatną stronę WWW nastąpi odczyt danych z bazy lub innego systemu, dane zostaną przekazane do aplikacji klienckiej, a następnie umieszczone na stronie WWW. Tak umieszczony kod zostanie wykonany za każdym razem, gdy uruchomiona zostanie podatna strona WWW. Przykładowymi miejscami wystąpienia podatności zapisanego XSS mogą być systemy komentarzy lub formularze kontaktowe.
- Reflected XSS – występuje, gdy udaje się wstrzyknąć skrypt do kodu strony, wykorzystując np. treść błędu, rezultaty wyszukiwania lub inne wyniki zwracane przez serwer zawierające skrypt przekazany w zapytaniu. Złośliwy kod może być przekazany np. przez parametry zapytań HTTP lub przez ciasteczka.
- DOM-based XSS – może wystąpić w momencie, gdy atakujący jest w stanie przekazać dane wejściowe do już istniejącego kodu JavaScript na podatnej stronie WWW i zmusić stronę do nieoczekiwanego zachowania.
W jaki sposób się rozwijasz swoje umiejętności programistyczne?
Nie jest to pytanie ściśle techniczne, niemniej jednak istnieje bardzo duża szansa, że je usłyszysz. Samych sposobów na rozwijanie swoich umiejętności programistycznych jest całkiem sporo i dla przedstawię tu kilka z nich:
- czytanie blogów programistycznych;
- pomaganie na forach i StackOverflow;
- bierny i czynny w konferencjach, meetupach, warsztatach i hackatonach;
- czytanie książek;
- oglądanie poradników;
- realizacja kursów i szkoleń;
- udział w szkołach programowania, bootcampach;
- studiowanie na kierunku technicznym;
- aktywny udział w grupach na Facebooku, Slackach i Discordach programistycznych;
- udział w konkursach;
- i co najważniejsze… praktyczne programowanie i realizacja projektów!
O rozwoju umiejętności programistycznych możesz poczytać więcej na moim blogu. Sprawdź koniecznie artykuły podlinkowane na końcu tego wpisu.
Czym jest Promise
w JavaScript?
Obiekt Promise
jest opakowaniem na wartość, która nie jest jeszcze znana w momencie tworzenia inicjalizacji Promise
. Wykorzystanie Promise
pozwala na obsłużenie zdarzeń asynchronicznych i pracę ze zwracanymi z nich wartościami. Zamiast oczekiwanej wartości, asynchroniczna metoda zwraca obiekt klasy Promise
w stanie pending. Po zakończeniu akcji asynchronicznej instancja Promise
może przyjąć wartość fulfilled (sukces) lub rejected (porażka). W momencie rozwiązania obietnicy, tzn. ustawienia jej stanu na fulfilled lub rejected, zwracana jest konkretna wartość, której oczekiwano w momencie utworzenia obietnicy.
Po wprowadzeniu do standardu podejścia async/await
możliwe jest pisanie kodu asynchronicznego w sposób, jaki pisze się kod synchroniczny.
const asyncFunction = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 2000);
});
};
asyncFunction()
.then(data => {
console.log('Resolve: ' + data);
})
.catch(error => {
console.error('Reject:' + error);
});
(async () => {
const data = await asyncFunction();
console.log('async/await: ' + data);
})();
[Pytanie bonusowe] Jaka jest różnica między Java a JavaScript?
Różnica między nimi jest mniej więcej taka jak pomiędzy ham i hamster lub krzesłem i krzesłem elektrycznym. Oczywiście jest to żart i nie należy traktować tego pytania poważnie. Możesz je zapamiętać i spróbować nim rozluźnić atmosferę w trakcie rozmowy 😉
Podsumowanie
Te kilkanaście pytań to o wiele za mało, by być dobrze przygotowanym do rozmowy rekrutacyjnej. Jeszcze raz gorąco zachęcam do sprawdzenia innych wpisów na blogu oraz pobranie e-booka 106 Pytań Rekrutacyjnych Junior JavaScript Developer. Zachęcam też do zostawiania komentarzy i udostępnienia tego wpisu znajomym, którym ta wiedza może się przydać.
Źródła i materiały dodatkowe
- Dlaczego warto brać udział w konkursach?
- Wartościowe kanały programistyczne na YouTube
- Rozwój umiejętności programistycznych
- Jak zacząć programować
- MDN – Falsy values
- How can I capture the right-click event in JavaScript?
- SASS and Bootstrap – mixins vs. @extend
- Efficiently load JavaScript with defer and async
- Cross Site Scripting (XSS)
- DOM Based XSS
- Promise – MDN
*Artykuł jest odświeżoną wersją wpisu z 2019 roku.
No nie do końca. To zdarzenie służy do przejęcia kontroli nad menu kontekstowym, które można także otworzyć z poziomu klawiatury (nie wszystkie klawiatury są tak wykastrowane jak makowa). Nad prawym przyciskiem myszy można zapanować albo przez zdarzenie auxclick, albo mouseup.
Dzięki za uzupełnienie, już poprawione 🙂
ad 1, takie podchwytliwe pytanko na rozmowę, sprawdzające, czy ktoś naprawę rozumie JS i obiekty 🙂
const value = new Boolean(false);
if (value) {
// czy to się wykona?
} else {
// czy może to?
}
Jak ktoś rozumie konwersję typów w JS to jest to oczywiste, ale może sprawdzić jakieś logiczne myślenie itp. 🙂 Ale tak po za tym to ja osobiście uważam takie pytanka za mało sensowne… na rozmowach rekrutacyjnych powinny być moim zdaniem rozmowy bardziej ogólne, np. jak zaprojektowałbyś przechowywanie koszyka z zakupami w aplikacji, czy jak podszedłbyś do tematu systemu rejestracji itp. Bez wchodzenia w szczegóły… nawet jak ktoś nie zna np. metody Array.prototype.filter gdy ktoś o nią pyta to w 5 sekund sobie wygoogla czy wyszuka w dokumentacji, takie pytania moim zdaniem nie sprawdzają za bardzo wiedzy a jedynie niepotrzebnie stresują. Natomiast np. rozmawiając o całym systemie rejestracji można wyczuć, czy ktoś ma faktycznie pojęcie czy za bardzo nie umie jeszcze „w programowanie” i w sumie dopiero zaczyna naukę… Ale to moje subiektywne zdanie.
Co do
jak najbardziej się zgodzę. Myślę, że nie ma większego sensu pytać „jak działa funkcja x?” , co nie zmienia faktu, że takie pytania padają o czym najlepiej świadczy fakt że jako źródło pytań wykorzystałem bazę danych tworzoną przez społeczność (w tym zapewne rekruterów).
Natomiast takie pytanie jak pytanie o falsy values warto zadać z kilku względów:
– osoba „umiejąca w programowanie” potraktuje je jako rozgrzewkę i dzięki temu będzie się czuła pewniej na rozmowie
– konkretnie to pytanie sprawdza też wiedzę z zakresu stosowania profesjonalnej terminologii., Zdecydowanie więcej źródeł (i zwykle też lepszej jakości) znajdziemy na frazę 'closures’ niż na frazę 'domknięcia’.
z tą rozgrzewką to bym uważał… ja generalnie jestem wielkim przeciwnikiem takich pytań typowo o język, funkcje, takie rzeczy składniowe itp. bo wiem po sobie, że gdy czasami w ciągu tygodnia muszę skakać między Angular/React na froncie raz z TS raz znowu bez TS itp. i do tego machnąć coś w node czy Springu to czasami człowiekowi się mieszają nazwy funkcji itp. czy nawet jakieś rzeczy proste składniowo ale od takich spraw jest IDE, dlatego taka moja opinia o tego typu pytaniach.
Hej, świetny artykuł 😀
Co do punktu 11, można dodać inne porównania xD (Car i Carpet albo Sam i Samochód).
Wydaje mi się, że w pytaniu dziewiątym flagi powinny zostać opatrzone podwójnym myślnikiem : )
Racja, do wpisu wkradł się mały chochlik. Dzięki za czujne oko 🙂
A ja dziękuję za artykuł, bo chciałem sobie pewną rzecz przypomnieć i znakomicie się czyta : )