Gdy aplikacja ma zareagować inaczej na kilka konkretnych wartości, rozbudowane if...else szybko staje się mało czytelne. Instrukcja switch w JavaScript porządkuje taki kod, ale ma kilka pułapek, przede wszystkim związanych z break, porównaniem typów i przypadkowym przechodzeniem do kolejnych przypadków. Pokażę, jak działa, kiedy jej używać, czym różni się od if...else i jak pisać ją tak, żeby kod był łatwy w utrzymaniu.
Switch najlepiej sprawdza się przy wielu konkretnych wariantach jednej wartości
-
switchporównuje wyrażenie z kolejnymi etykietamicase. - Porównanie odbywa się tak jak przy ścisłym porównaniu
===, bez automatycznej konwersji typów. -
breakzatrzymuje wykonanie i chroni przed przejściem do następnego przypadku. -
defaultobsługuje wartość, dla której nie zdefiniowano osobnegocase. - Brak
breakmoże być błędem, ale czasem świadomie wykorzystuje się go do łączenia kilku przypadków.

Jak działa instrukcja switch w JavaScript
switch przyjmuje jedno wyrażenie, a potem sprawdza je względem wartości zapisanych przy kolejnych case. Po znalezieniu dopasowania JavaScript uruchamia kod od tego miejsca i wykonuje go aż do napotkania break albo końca całej instrukcji.
const status = "gotowy";
switch (status) {
case "gotowy":
console.log("Możesz rozpocząć pracę");
break;
case "w trakcie":
console.log("Operacja nadal trwa");
break;
case "zakończony":
console.log("Operacja została zakończona");
break;
default:
console.log("Nieznany status");
}
W tym przykładzie tylko jeden blok zostanie wykonany, ponieważ każdy przypadek kończy się instrukcją break. To najczęstszy i najbardziej przewidywalny sposób korzystania z tego mechanizmu.
Istotny szczegół polega na tym, że case nie tworzy osobnego zakresu zmiennych. Gdy deklarujesz wewnątrz przypadków zmienne za pomocą let lub const, dobrze jest użyć klamrowych bloków, szczególnie w większych instrukcjach. Dzięki temu unikasz konfliktów nazw i łatwiej kontrolujesz zakres kodu.
const typKonta = "premium";
switch (typKonta) {
case "premium": {
const limit = 1000;
console.log(`Limit wynosi ${limit}`);
break;
}
case "standard": {
const limit = 100;
console.log(`Limit wynosi ${limit}`);
break;
}
}
Case, break i default w praktycznych przykładach
Wartości tekstowe i liczbowe
Instrukcja może pracować z tekstami, liczbami, wartościami logicznymi, a nawet symbolami. Typ ma znaczenie, ponieważ dopasowanie jest ścisłe. Liczba 1 nie pasuje do tekstu "1".
const kod = 1;
switch (kod) {
case "1":
console.log("To tekst");
break;
case 1:
console.log("To liczba");
break;
default:
console.log("Brak dopasowania");
}
Wynik to „To liczba”. Początkujący często zakładają, że JavaScript sam zamieni typy, tak jak przy niektórych operacjach z użyciem ==. W switch takie założenie prowadzi do trudnych do zauważenia błędów, dlatego przed napisaniem przypadków sprawdzam, jaki typ naprawdę zwraca dane wyrażenie.
Domyślna reakcja
Blok default działa wtedy, gdy żaden case nie pasuje. Nie jest obowiązkowy, ale w kodzie obsługującym dane od użytkownika, adres URL albo odpowiedź serwera zwykle warto go dodać.
const metodaPlatnosci = "blik";
switch (metodaPlatnosci) {
case "karta":
console.log("Płatność kartą");
break;
case "przelew":
console.log("Płatność przelewem");
break;
default:
console.log("Wybrana metoda nie jest obsługiwana");
}
default nie powinien maskować problemu. Jeśli aplikacja dopuszcza tylko trzy wartości, a pojawia się czwarta, lepiej zalogować błąd albo pokazać jasny komunikat niż po cichu wykonać przypadkową ścieżkę.
Co się stanie bez break
Brak break powoduje tak zwany fall-through, czyli przejście do kodu kolejnego przypadku. JavaScript nie zatrzymuje się automatycznie po wykonaniu dopasowanego bloku.
const poziom = 2;
switch (poziom) {
case 1:
console.log("Poziom podstawowy");
case 2:
console.log("Poziom średni");
case 3:
console.log("Poziom zaawansowany");
}
Dla wartości 2 zostaną wyświetlone dwa komunikaty, dotyczące poziomu średniego i zaawansowanego. W większości przypadków to pomyłka. Świadomy fall-through ma sens wtedy, gdy kilka wartości powinno uruchomić dokładnie tę samą logikę.
const dzien = "sobota";
switch (dzien) {
case "sobota":
case "niedziela":
console.log("To dzień wolny");
break;
default:
console.log("To dzień roboczy");
}
Taki zapis jest czytelny, bo oba dni prowadzą do jednego wyniku. Jeżeli pominięcie break ma być celowe, dobrze zaznaczyć to komentarzem, zwłaszcza w projekcie zespołowym.
Kiedy switch jest lepszy od if...else
Najprościej przyjąć, że switch pasuje do sytuacji, w której porównujesz jedną wartość z wieloma konkretnymi możliwościami. Przykładem może być status zamówienia, typ użytkownika, nazwa widoku albo rodzaj akcji wykonanej w interfejsie.
| Sytuacja | Lepszy wybór | Dlaczego |
|---|---|---|
| Jedna wartość i wiele dokładnych wariantów | switch |
Przypadki są uporządkowane i łatwe do przeskanowania. |
| Zakresy, np. wynik od 0 do 49 | if...else |
Warunki opisują relacje typu <, >= i &&. |
| Kilka niezależnych warunków | if...else |
Każdy warunek może sprawdzać inną zmienną lub regułę. |
| Proste mapowanie nazwy na funkcję | Obiekt lub mapa | Dane i zachowanie można oddzielić od instrukcji sterującej. |
Na przykład ocena punktowa lepiej pasuje do if...else, ponieważ sprawdza przedziały:
const punkty = 78;
if (punkty >= 90) {
console.log("Ocena bardzo dobra");
} else if (punkty >= 70) {
console.log("Ocena dobra");
} else if (punkty >= 50) {
console.log("Ocena dostateczna");
} else {
console.log("Ocena niedostateczna");
}
Z kolei wybór komunikatu na podstawie dokładnego statusu jest naturalnym zastosowaniem switch. Nie próbuję zamieniać każdego łańcucha if...else na tę instrukcję, bo przy warunkach logicznych kod często staje się wtedy mniej zrozumiały.
Praktyczne zastosowania w kodzie aplikacji
Obsługa akcji użytkownika
W aplikacji internetowej często mamy jedną nazwę akcji i kilka możliwych reakcji. Zamiast wielu porównań można uporządkować je w jednym miejscu.
function obsluzAkcje(akcja) {
switch (akcja) {
case "otworz":
console.log("Otwieram panel");
break;
case "zapisz":
console.log("Zapisuję dane");
break;
case "usun":
console.log("Usuwam rekord");
break;
default:
console.warn("Nieznana akcja");
}
}
obsluzAkcje("zapisz");
Ten układ jest wygodny, gdy lista akcji jest zamknięta i niezbyt długa. Przy kilkunastu lub kilkudziesięciu wariantach rozważam osobne funkcje i obiekt mapujący akcje na zachowania, ponieważ jedna ogromna instrukcja zaczyna utrudniać testowanie.
Obsługa widoków i routingu
switch sprawdza się także przy prostym przełączaniu widoków na podstawie ścieżki lub identyfikatora ekranu. W prawdziwym routerze używa się zwykle gotowych mechanizmów frameworka, ale do małego projektu lub ćwiczenia taki zapis jest wystarczający.
const widok = "profil";
switch (widok) {
case "start":
pokazStart();
break;
case "profil":
pokazProfil();
break;
case "ustawienia":
pokazUstawienia();
break;
default:
pokazBlad404();
}
Najważniejsza zasada brzmi tutaj normalizuj dane przed porównaniem. Jeśli wartość może zawierać wielkie litery lub przypadkowe spacje, przygotuj ją wcześniej, na przykład przez trim() i toLowerCase(). W przeciwnym razie poprawny logicznie przypadek może nie zostać rozpoznany.
Zaawansowane warianty i częste pułapki
Switch z true
Technika switch (true) pozwala sprawdzać warunki logiczne, ponieważ każdy case zwraca wartość true albo false.
const temperatura = 28;
switch (true) {
case temperatura >= 30:
console.log("Jest bardzo gorąco");
break;
case temperatura >= 20:
console.log("Temperatura jest przyjemna");
break;
default:
console.log("Jest chłodno");
}
To działa, ale nie zawsze poprawia czytelność. Przy kilku prostych przedziałach zwykłe if...else zazwyczaj mówi wprost, co się dzieje. Traktuję switch (true) jako narzędzie pomocnicze, a nie uniwersalny zamiennik warunków.
Return zamiast break
Jeśli switch znajduje się w funkcji, return może zakończyć ją wcześniej. W takim przypadku nie potrzebujesz dodatkowego break, bo funkcja przestaje wykonywać dalszy kod.
function etykietaStatusu(status) {
switch (status) {
case "nowy":
return "Nowe zamówienie";
case "wyslany":
return "Zamówienie wysłane";
case "anulowany":
return "Zamówienie anulowane";
default:
return "Nieznany status";
}
}
To rozwiązanie jest zwięzłe, ale używam go wtedy, gdy każdy przypadek rzeczywiście zwraca wynik. Jeśli blok wykonuje kilka operacji, zapis z break może być łatwiejszy do debugowania.
Przeczytaj również: instanceof w JavaScript - Używać czy unikać?
Obiekt jako alternatywa
Przy prostym mapowaniu wartości na tekst często wystarczy obiekt. Taki wariant usuwa powtarzające się case i bywa wygodny, gdy przypadki nie wykonują rozbudowanej logiki.
const komunikaty = {
sukces: "Operacja zakończona powodzeniem",
blad: "Operacja nie powiodła się",
oczekiwanie: "Operacja jest w toku"
};
const status = "sukces";
console.log(komunikaty[status] ?? "Nieznany status");
Obiekt nie zastąpi jednak switch w każdej sytuacji. Gdy poszczególne warianty mają różne instrukcje, walidację albo kilka kroków działania, jawne przypadki nadal mogą być czytelniejsze.
Jak pisać switch bez błędów
Najwięcej problemów wynika nie z samej składni, lecz z niejasnych danych wejściowych i przypadkowego przepływu wykonania. Przed zatwierdzeniem kodu sprawdzam kilka rzeczy.
- Czy wszystkie wartości w
casemają właściwy typ? - Czy każdy przypadek, który nie ma celowo przechodzić dalej, kończy się
breakalboreturn? - Czy
defaultobsługuje nieznane i niepoprawne dane? - Czy warunki nie dotyczą zakresów, dla których lepsze będzie
if...else? - Czy nazwy przypadków są spójne z wartościami zwracanymi przez API lub formularz?
Dobrym zwyczajem jest także włączenie reguły no-fallthrough w ESLint. Narzędzie ostrzeże o przypadkach, w których kod przechodzi do kolejnej etykiety bez wyraźnego zakończenia. Nie zastąpi testów, ale szybko wyłapuje jedną z najbardziej typowych pomyłek.
Nie komplikowałbym też instrukcji dodatkowymi zagnieżdżeniami. Jeżeli pojedynczy case ma kilkadziesiąt linii, wydziel jego logikę do osobnej funkcji. Dzięki temu sam switch pozostaje krótką mapą decyzji, a szczegóły działania są testowalne osobno.
Mała decyzja, która robi dużą różnicę w czytelności kodu
Instrukcja switch jest dobrym wyborem dla wielu dokładnych wariantów jednej wartości. Zapamiętaj trzy elementy: porównanie jest ścisłe, break zatrzymuje dalsze wykonanie, a default zabezpiecza kod przed nieobsłużonym przypadkiem.
W praktyce najbardziej opłaca się używać jej oszczędnie i świadomie. Gdy potrzebujesz zakresów, złożonych warunków albo niezależnych reguł, wybierz if...else; gdy mapujesz proste klucze na dane, rozważ obiekt. Taki dobór narzędzia sprawia, że kod JavaScript pozostaje przewidywalny także wtedy, gdy aplikacja zaczyna rosnąć.