• Aplikacje webowe
  • Switch w JavaScript - składnia, przykłady i typowe błędy

Switch w JavaScript - składnia, przykłady i typowe błędy

Radosław Krajewski 8 lipca 2026
Schemat blokowy przedstawia działanie instrukcji switch w JS. Wartość jest porównywana z kolejnymi case'ami, a po znalezieniu dopasowania wykonuje się odpowiedni blok kodu.

Spis treści

Gdy aplikacja webowa ma reagować na kilka konkretnych stanów, ról użytkownika albo typów zdarzeń, seria instrukcji if...else szybko staje się trudna do czytania. Konstrukcja switch pozwala uporządkować taki kod, ale tylko wtedy, gdy rozumiesz działanie case, break i default. Pokażę składnię, praktyczne przykłady, typowe błędy oraz sytuacje, w których lepiej wybrać if...else albo mapę obiektów.

Najważniejsze zasady używania switch w JavaScript

  • switch porównuje jedną wartość z kolejnymi przypadkami za pomocą ścisłego porównania.
  • break zatrzymuje wykonanie, aby kod nie przeszedł przypadkowo do następnego case.
  • default obsługuje wartości, których nie przewidziano wcześniej.
  • Grupowanie case dobrze sprawdza się wtedy, gdy kilka wartości prowadzi do tej samej akcji.
  • if...else jest czytelniejsze przy zakresach i złożonych warunkach.

Schemat blokowy przedstawia działanie instrukcji switch w JS. Wartość jest porównywana z kolejnymi case'ami, a po znalezieniu dopasowania wykonuje się odpowiedni blok kodu.

Jak działa switch w JavaScript

switch przyjmuje jedną wartość, a potem porównuje ją z wyrażeniami zapisanymi przy kolejnych etykietach case. JavaScript używa tu odpowiednika operatora ===, więc typ wartości ma znaczenie. Tekst "1" nie pasuje do liczby 1, co jest jednym z częstszych źródeł niespodzianek.

Podstawowa konstrukcja wygląda tak:

switch (wartosc) {
  case "a":
    // instrukcje dla wartości "a"
    break;

  case "b":
    // instrukcje dla wartości "b"
    break;

  default:
    // obsługa nieznanej wartości
}

Po znalezieniu pasującego przypadku wykonywanie zaczyna się od jego instrukcji. Bez break kod przejdzie dalej i wykona również kolejne przypadki. Dokumentacja MDN opisuje to zachowanie jako fall-through, czyli przejście wykonania do następnych etykiet.

Element Rola Praktyczna uwaga
switch Wskazuje wartość podlegającą sprawdzeniu. Najlepiej używać go dla jednej zmiennej lub jednego wyrażenia.
case Definiuje konkretną wartość. Porównanie jest ścisłe, bez automatycznej konwersji typu.
break Kończy wykonanie konstrukcji. Nie jest potrzebny przed return albo throw.
default Obsługuje brak dopasowania. Przydaje się jako bezpieczna ścieżka dla nieznanych danych.

Traktuję default jako mały bezpiecznik. Dane z API, parametr adresu URL albo wartość przechowywana w bazie mogą kiedyś przyjąć nową postać. Dzięki temu interfejs nie kończy się pustym komunikatem tylko dlatego, że backend zwrócił status, którego frontend jeszcze nie zna.

Podstawowy przykład w aplikacji webowej

Dobrym zastosowaniem jest wyświetlanie komunikatu zależnego od statusu zamówienia. W tym przypadku mamy jedną wartość i kilka jasno określonych możliwości, więc switch pozostaje czytelny nawet po dodaniu kolejnych stanów.

function getOrderMessage(status) {
  switch (status) {
    case "new":
      return "Zamówienie zostało przyjęte.";

    case "paid":
      return "Płatność została zaksięgowana.";

    case "shipped":
      return "Przesyłka jest już w drodze.";

    case "cancelled":
      return "Zamówienie zostało anulowane.";

    default:
      return "Status zamówienia jest nieznany.";
  }
}

const message = getOrderMessage("shipped");
console.log(message);

W tym przykładzie każde case kończy się przez return, więc nie trzeba dodawać break. Funkcja natychmiast zwraca wynik i opuszcza swoje wykonanie. To jeden z moich ulubionych sposobów zapisu, ponieważ ogranicza ryzyko przypadkowego fall-through.

Podobny mechanizm można wykorzystać przy renderowaniu widoku, wyborze komunikatu walidacyjnego albo obsłudze odpowiedzi HTTP. Trzeba jednak pamiętać, że sama konstrukcja nie wykonuje żadnego mapowania automatycznie. To programista decyduje, co ma się stać dla każdego stanu.

function getResponseAction(statusCode) {
  switch (statusCode) {
    case 200:
      return "Pokaż dane użytkownika.";

    case 401:
      return "Przekieruj do logowania.";

    case 403:
      return "Pokaż komunikat o braku uprawnień.";

    case 404:
      return "Pokaż stronę nie znaleziono.";

    case 500:
      return "Pokaż komunikat o błędzie serwera.";

    default:
      return "Obsłuż nieznaną odpowiedź.";
  }
}

Ten wariant działa dobrze, gdy lista kodów jest krótka i zamknięta. Jeżeli przypadków zaczyna być kilkanaście, a każdy uruchamia rozbudowaną logikę, lepiej przenieść poszczególne operacje do osobnych funkcji. Sam switch nie powinien stawać się wielką procedurą z logiką biznesową, obsługą formularza i komunikacją z API w jednym miejscu.

break, fall-through i kilka wartości dla jednej akcji

Najczęstszy błąd wygląda niewinnie. Programista dopisuje kod w jednym case, zapomina o break i nagle po jednej akcji uruchamia się kod przeznaczony dla kolejnego przypadku.

const role = "user";

switch (role) {
  case "user":
    console.log("Panel użytkownika");

  case "admin":
    console.log("Panel administracyjny");
    break;

  default:
    console.log("Brak dostępu");
}

Dla wartości "user" zostaną wypisane oba komunikaty. JavaScript nie traktuje kolejnego case jak automatycznej granicy bloku. W praktyce dodaję break od razu po zakończeniu każdej niezależnej gałęzi, chyba że przejście dalej jest świadomą decyzją.

Brak break może być celowy, gdy kilka wartości ma prowadzić do tej samej instrukcji. Wtedy zapisujemy przypadki jeden pod drugim:

function getLanguageMessage(language) {
  switch (language) {
    case "pl":
    case "en":
      return "Dostępna jest wersja strony.";

    case "de":
      return "Die deutsche Version ist verfügbar.";

    default:
      return "Wybrany język nie jest obsługiwany.";
  }
}

W tym przykładzie "pl" i "en" są grupą. Żaden z tych przypadków nie ma własnych instrukcji, więc wykonanie dochodzi do wspólnego return. Taki zapis jest czytelny, ale dobrze zostawić krótką uwagę w komentarzu, jeśli grupowanie nie wynika od razu z kodu.

Istnieją też sytuacje, w których fall-through wykonuje kilka etapów po kolei. To jednak rozwiązanie dla doświadczonych osób i wymaga komentarza wyjaśniającego intencję. Bez tego kolejny programista może potraktować brak break jak zwykłą pomyłkę i „naprawić” działający kod.

switch czy if...else albo mapa obiektów

Nie każda seria warunków potrzebuje switch. Ja wybieram tę konstrukcję wtedy, gdy sprawdzam jedną wartość względem kilku konkretnych możliwości. Przy zakresach, operatorach logicznych i warunkach zależnych od kilku zmiennych zwykle lepiej wypada if...else.

Rozwiązanie Najlepsze zastosowanie Ograniczenie
switch Statusy, role, typy zdarzeń i kody odpowiedzi. Słabiej radzi sobie z zakresami i wieloma warunkami.
if...else Warunki typu „większe niż”, przedziały i złożone wyrażenia. Przy wielu równych porównaniach kod może stać się rozwlekły.
Mapa obiektów Proste przypisanie wartości do etykiet, funkcji albo konfiguracji. Nie zawsze pasuje do rozbudowanej logiki i efektów ubocznych.

Przykład warunku zakresowego jest prostszy z użyciem if...else:

function getDiscount(points) {
  if (points >= 1000) {
    return 20;
  }

  if (points >= 500) {
    return 10;
  }

  return 0;
}

Próba zapisania tego jako zwykłych przypadków byłaby błędem. Konstrukcja case points >= 1000 porównywałaby liczbę punktów z wartością logiczną true, a nie sprawdzała zakres w sposób, którego można intuicyjnie oczekiwać.

Jeśli potrzebujesz wyłącznie prostego słownika, mapa obiektów bywa krótsza:

const labels = {
  pending: "Oczekuje na płatność",
  paid: "Opłacone",
  shipped: "Wysłane"
};

function getLabel(status) {
  return labels[status] ?? "Nieznany status";
}

Mapa dobrze oddziela dane od logiki. Z drugiej strony switch daje więcej miejsca na walidację, wywołanie funkcji, zapis do logów albo różne działania dla każdej wartości. Nie kierowałbym się więc samą długością kodu. Ważniejsze jest to, czy czytelnik od razu rozumie, czy mamy mapowanie danych, czy proces decyzyjny.

Typowe błędy i praktyki, które poprawiają kod

Brak break w niezależnym przypadku

Jeżeli gałąź nie kończy się przez return, throw albo inną świadomą konstrukcję, dodaj break. Błąd jest szczególnie zdradliwy przy kodzie interfejsu, ponieważ efekt może pojawić się dopiero po wybraniu konkretnej kombinacji danych.

Nieprawidłowy typ wartości

Wartość pobrana z formularza lub adresu URL zwykle jest tekstem. Dlatego switch (input) nie dopasuje case 1, jeśli input ma wartość "1". Zanim zaczniesz szukać problemu w samym case, sprawdź typ przez typeof i ujednolić dane na wejściu.

const page = Number(new URLSearchParams(location.search).get("page"));

switch (page) {
  case 1:
    console.log("Pierwsza strona");
    break;

  default:
    console.log("Inna strona");
}

Brak obsługi wartości nieznanych

default nie zawsze jest formalnie wymagany, ale w aplikacjach webowych zwykle warto go dodać. Może zwrócić bezpieczny komunikat, uruchomić logowanie albo zatrzymać dalsze przetwarzanie. Szczególnie niebezpieczne jest ciche pomijanie nowego statusu zwróconego przez API.

Próba użycia zakresów w case

Standardowy switch nie jest konstrukcją do sprawdzania przedziałów. W takich sytuacjach można spotkać wzorzec switch (true), ale zwykle nie poprawia on czytelności:

switch (true) {
  case score >= 90:
    return "bardzo dobry";

  case score >= 60:
    return "dobry";

  default:
    return "wymaga poprawy";
}

Ten zapis działa, ponieważ kolejne przypadki zwracają wartości logiczne, które są porównywane z true. Mimo to przy kilku progach częściej wybrałbym if...else. Jest bardziej oczywiste dla osoby, która utrzymuje kod po kilku miesiącach.

Przeczytaj również: Bootstrap spinner - jak wdrożyć ładowanie i dostępność

Zmienne deklarowane bez własnego bloku

Etykiety case nie tworzą automatycznie osobnego zakresu dla let i const. Jeżeli w kilku przypadkach deklarujesz zmienne o tych samych nazwach, możesz otrzymać błąd składni. Rozwiązaniem jest zamknięcie instrukcji danego przypadku w nawiasach klamrowych.

switch (status) {
  case "ready": {
    const message = "Gotowe";
    console.log(message);
    break;
  }

  case "error": {
    const message = "Wystąpił błąd";
    console.log(message);
    break;
  }

  default: {
    console.log("Nieznany status");
  }
}

Nie stosuję dodatkowych bloków bez powodu, ale przy większych przypadkach poprawiają one izolację zmiennych. To drobny szczegół, który oszczędza później czasu podczas refaktoryzacji.

Jak pisać switch, który dobrze znosi rozwój aplikacji

Najprostsza zasada brzmi: każdy przypadek powinien mieć jedną wyraźną odpowiedzialność. Jeśli jedna gałąź aktualizuje widok, zapisuje dane i wysyła żądanie do serwera, przenieś te operacje do osobnej funkcji. Wtedy switch wybiera działanie, ale nie przejmuje całej logiki aplikacji.

Przy większych projektach dobrze jest również ustalić, jakie wartości są dozwolone. Statusy takie jak "pending", "paid" i "shipped" powinny pochodzić z jednego uzgodnionego modelu, a nie być wpisywane ręcznie w kilkunastu komponentach. Ogranicza to literówki, które w przypadku stringów nie zawsze są widoczne podczas przeglądania kodu.

Dobrym testem jakości jest sprawdzenie trzech sytuacji: każdego znanego przypadku, wartości nieznanej oraz wartości o nieprawidłowym typie. Jeśli funkcja zachowuje się rozsądnie we wszystkich trzech, konstrukcja jest znacznie bardziej odporna na zmiany po stronie formularza, API i interfejsu.

Nie próbowałbym też na siłę skracać dużego switch. Dwanaście prostych przypadków może być czytelniejsze niż skomplikowana mapa funkcji, a trzy przypadki z rozbudowaną logiką mogą uzasadniać osobne funkcje. Liczba gałęzi jest wskazówką, ale o wyborze powinien decydować charakter problemu.

Najlepszy switch to ten, którego intencję widać od razu

switch sprawdza się przy skończonej liczbie jasno nazwanych wartości. Zapamiętaj trzy rzeczy: porównanie jest ścisłe, break chroni przed przypadkowym przejściem dalej, a default obsługuje świat, który zwykle jest większy niż nasze założenia.

W codziennym kodzie aplikacji webowej nie wybieram tej konstrukcji dlatego, że jest krótsza od if...else. Wybieram ją wtedy, gdy pokazuje decyzję w sposób naturalny. Jeśli po kilku sekundach wiadomo, jaka wartość prowadzi do jakiej akcji, rozwiązanie jest prawdopodobnie dobrze dopasowane.

FAQ - Najczęstsze pytania

Switch używa ścisłego porównania, odpowiednika operatora ===, dlatego tekst "1" nie pasuje do case 1. Warto sprawdzić typ przez typeof albo ujednolicić dane na wejściu, na przykład konwertując parametr URL za pomocą Number().

Brak break powoduje fall-through, czyli przejście do instrukcji kolejnego case. Jest błędem, gdy niezależna gałąź ma zakończyć działanie, ale może być celowy, gdy kilka wartości ma prowadzić do tej samej akcji, jak case "pl" i case "en" przed wspólnym return.

If...else jest czytelniejsze przy zakresach, operatorach logicznych i warunkach zależnych od kilku zmiennych. Na przykład progi rabatowe dla 1000 i 500 punktów łatwiej zapisać za pomocą if (points >= 1000) oraz kolejnych warunków.

W takiej sytuacji można użyć mapy obiektów, która oddziela dane od logiki. Przykładowo labels[status] ?? "Nieznany status" zwróci etykietę dla statusu pending, paid lub shipped, a dla nieznanej wartości bezpieczny tekst zastępczy.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

javascript
switch
if...else
fall-through
mapowanie
Autor Radosław Krajewski
Radosław Krajewski
Nazywam się Radosław Krajewski i od 6 lat zgłębiam tajniki programowania .NET, chmury Azure oraz sztucznej inteligencji. Moja przygoda z tymi technologiami zaczęła się od fascynacji tym, jak złożone problemy można rozwiązywać za pomocą kodu i innowacyjnych narzędzi. Staram się przekazywać tę wiedzę w sposób zrozumiały, dzieląc się swoimi doświadczeniami i spostrzeżeniami na kursdotnet.pl. W moich artykułach skupiam się na praktycznych aspektach, porównuję różne rozwiązania i analizuję najnowsze trendy, aby dostarczyć Wam rzetelne i aktualne informacje, które pomogą Wam rozwijać się w tej dynamicznie zmieniającej się dziedzinie.

Udostępnij artykuł

Napisz komentarz