Instrukcje warunkowe umożliwiają wykonanie różnych bloków kodu w zależności od spełnienia określonych warunków. Innymi słowy, pozwalają programowi podjąć decyzję: jeśli dany warunek jest prawdziwy, wykonaj pewne czynności, a jeśli nie – wykonaj inne (lub pomiń je). Dzięki temu program może reagować na różne sytuacje i dane wejściowe w sposób dynamiczny. Podstawową instrukcją warunkową w JavaScript (jak i w wielu innych językach) jest instrukcja if
.
Instrukcja if
(jeżeli)
Instrukcja if
sprawdza wybrany warunek logiczny i jeśli warunek ten zwróci true
(prawdę), wykonywany jest blok kodu znajdujący się wewnątrz instrukcji. Jeżeli warunek jest false
(fałsz), kod ten zostanie pominięty. Ogólna postać (składnia) instrukcji if
jest następująca:
if (warunek) {
// kod do wykonania, gdy warunek jest prawdziwy (true)
}
- Słowo kluczowe
if
rozpoczyna instrukcję warunkową. - W nawiasach okrągłych
()
umieszczamy warunek logiczny – jest to wyrażenie, które zostanie obliczone do wartościtrue
lubfalse
(często używamy tutaj operatorów porównania i logicznych, omówionych wcześniej). - Jeśli warunek jest spełniony (
true
), wykonany zostanie kod zawarty wewnątrz nawiasów klamrowych{ ... }
. - Jeśli warunek jest niespełniony (
false
), kod wewnątrz klamr zostanie pominięty (przeskoczony).
Rozważmy prosty przykład: chcemy sprawdzić, czy liczba w zmiennej x
jest dodatnia. Jeżeli tak, wypiszemy komunikat w konsoli.
let x = 5;
if (x > 0) {
console.log("x jest liczbą dodatnią");
}
W powyższym kodzie warunek to x > 0
. Dla x
równego 5 warunek ten jest prawdziwy, więc wewnątrz bloku if
zostanie wykonana instrukcja console.log(...)
i w konsoli zobaczymy napis „x jest liczbą dodatnią”. Gdyby zmienna x
miała wartość ujemną lub zero, warunek x > 0
byłby fałszywy i tym samym ciało instrukcji if
zostałoby pominięte (w tym przypadku program nic by nie wypisał).
Ważna uwaga: Jeżeli kod do wykonania po if
składa się tylko z jednej instrukcji, często w JavaScript spotyka się pominięcie nawiasów klamrowych (pisząc np. if (warunek) instrukcja;
). Jednakże zaleca się zawsze używać { ... }
dla czytelności i unikania błędów, szczególnie w kodzie początkujących – ułatwia to rozbudowę warunku o kolejne instrukcje.
Blok if...else
(jeżeli… w przeciwnym razie)
Sama instrukcja if
pozwala wykonać kod, gdy warunek jest spełniony. Często jednak chcemy również zdefiniować, co powinno się stać, gdy warunek nie jest spełniony. Służy do tego rozszerzenie else
. Konstrukcja if...else
wygląda tak:
if (warunek) { // kod gdy warunek jest true
} else {
// kod gdy warunek jest false
}
Działanie jest następujące: jeśli warunek
jest prawdą, wykona się pierwszy blok (po if
), natomiast jeżeli warunek okaże się fałszem – zostanie wykonany alternatywny blok po słowie kluczowym else
. Zawsze dokładnie jeden z tych dwóch bloków zostanie wykonany (nie ma możliwości, by wykonały się oba, albo by pominąć oba – jedna z gałęzi zostanie wybrana w zależności od warunku).
Przykład: Sprawdźmy, czy liczba w zmiennej x
jest parzysta czy nieparzysta i poinformujmy o tym:
let x = 7;
if (x % 2 == 0) {
console.log(x + " jest liczbą parzystą");
} else {
console.log(x + " jest liczbą nieparzystą");
}
W tym kodzie warunkiem jest x % 2 == 0
, czyli „czy reszta z dzielenia x
przez 2 wynosi 0″. To standardowy sposób sprawdzenia parzystości liczby – liczby parzyste dają resztę 0 przy dzieleniu przez 2. Dla x = 7
warunek ten jest fałszywy (7 % 2 to 1, nie 0), więc zostanie wykonany blok w części else
. Program wypisze: „7 jest liczbą nieparzystą”. Gdyby x
wynosiło np. 8, warunek x % 2 == 0
byłby prawdziwy i wykonany zostałby pierwszy blok, wypisując „8 jest liczbą parzystą”.
Wielokrotne warunki: if...else if...else
Często zdarza się, że potrzebujemy sprawdzić więcej niż jeden warunek i w zależności od tego, który z nich jest spełniony, wykonać różne czynności. Możemy łączyć wiele instrukcji warunkowych, wykorzystując konstrukcję else if
. Jej składnia to po prostu dodatkowy if
po początkowym if
, poprzedzony słowem else
:
if (warunek1) {
// kod gdy warunek1 jest true
} else if (warunek2) {
// kod gdy warunek1 jest false, a warunek2 jest true
} else if (warunek3) {
// kod gdy warunek1 i warunek2 są false, a warunek3 jest true
} else {
// kod gdy żaden z powyższych warunków nie jest spełniony
}
Możemy tu mieć dowolną liczbę sekcji else if
(nawet zero lub wiele), a na końcu opcjonalny blok else
na wypadek, gdy żaden z wcześniejszych warunków nie będzie prawdziwy. Program przechodzi od góry na dół przez kolejne warunki:
- Jeśli
warunek1
jest spełniony, wykona jego blok i pominie resztę (pozostałe warunki nie są już sprawdzane). - Jeśli
warunek1
jest fałszywy, za towarunek2
jest prawdziwy – wykonuje blokelse if
i kończy całą konstrukcję. - Jeśli pierwsze dwa warunki są fałszywe, a
warunek3
jest prawdziwy – wykona się trzecia gałąź. - Jeśli żaden z warunków 1, 2, 3 nie był prawdą, wykona się na końcu blok
else
(o ile został podany).
Przykład: Mamy zmienną temp
z bieżącą temperaturą (w stopniach Celsjusza) i chcemy skategoryzować pogodę na podstawie tej temperatury:
let temp = 18; if (temp >= 30) {
console.log("Bardzo gorąco");
} else if (temp >= 20) {
console.log("Ciepło");
} else if (temp >= 10) {
console.log("Chłodno");
} else {
console.log("Zimno");
}
W tym kodzie sprawdzamy kolejno:
- Czy
temp >= 30
(np. 30°C lub więcej to bardzo gorąco). Jeśli tak, wypisujemy odpowiedni komunikat i pomijamy resztę. - Jeśli pierwszy warunek nie był spełniony, sprawdzamy
temp >= 20
(20–29°C uznajemy za ciepło). - Jeśli to również było fałszem, sprawdzamy
temp >= 10
(10–19°C traktujemy jako chłodno). - Jeśli żadna z powyższych granic nie została osiągnięta (czyli mamy poniżej 10°C), w bloku
else
dajemy komunikat „Zimno”.
Dla temp = 18
spełniony jest dopiero trzeci warunek (temp >= 10
), więc na konsoli zobaczymy napis „Chłodno”. Gdyby temp
wynosiło 32, już pierwszy warunek byłby spełniony i program od razu wypisałby „Bardzo gorąco”, nie sprawdzając reszty. Konstrukcja if...else if...else
jest czytelnym sposobem obsługi wielu wzajemnie wykluczających się warunków.
Zagnieżdżone instrukcje warunkowe
Warto wspomnieć, że instrukcje warunkowe można zagłębiać (zagnieżdżać) wewnątrz siebie. Oznacza to, że wewnątrz bloku if
lub else
możemy umieścić kolejny if
. Takie podejście czasem bywa potrzebne, choć należy stosować je ostrożnie, by kod nie stał się zbyt skomplikowany w czytaniu. Alternatywą bywa często użycie operatorów logicznych, aby połączyć warunki w jednym if
(zamiast dwóch osobnych zagnieżdżonych). Dla przykładu spójrzmy na dwa równoważne fragmenty kodu:
// Wariant zagnieżdżony
let username = "Admin";
let password = "1234";
if (username == "Admin") {
if (password == "1234") {
console.log("Logowanie powiodło się");
}
}
// Wariant z łączeniem warunków logicznych
if (username == "Admin" && password == "1234") {
console.log("Logowanie powiodło się");
}
Oba przykłady sprawdzają, czy jednocześnie username
jest równe „Admin” i password
jest równe „1234”. Pierwszy robi to poprzez zagnieżdżenie (drugi if
wewnątrz pierwszego), drugi zaś wykorzystuje operator logiczny &&
w jednym warunku. Rezultat działania obu fragmentów jest taki sam – w konsoli pojawi się komunikat o poprawnym logowaniu tylko jeśli oba warunki są spełnione. Widać, że druga wersja jest bardziej zwięzła i czytelna, dlatego warto łączyć warunki logiczne zamiast nadmiernie zagnieżdżać if
, tam gdzie to możliwe.
Instrukcja switch
Instrukcja switch
to alternatywny sposób obsługi warunkowego sterowania programem, szczególnie przydatny, gdy mamy wiele możliwych wartości jednej zmiennej lub wyrażenia i dla każdej z tych wartości chcemy wykonać inny kod. Składnia instrukcji switch
jest nieco odmienna od if
, opiera się na pojęciu przypadków (ang. cases):
switch (wyrażenie) {
case wartość1:
// kod do wykonania, gdy wyrażenie == wartość1
break;
case wartość2:
// kod dla przypadku, gdy wyrażenie == wartość2
break;
// ... (kolejne przypadki case w razie potrzeby)
default:
// kod do wykonania, gdy wyrażenie nie pasuje do żadnego powyższego przypadku
break;
}
Działanie switch
jest następujące:
- Najpierw obliczane jest podane wyrażenie (w nawiasie po słowie
switch
). Często jest to po prostu zmienna, którą chcemy sprawdzić. - Następnie wartość tego wyrażenia jest porównywana kolejno z każdą z podanych po
case
wartości:- Jeśli zostanie znaleziony odpowiadający przypadek (
case
), wykonywany jest kod następujący po dwukropku:
. - Instrukcja
break
na końcu każdego przypadku powoduje wyjście ze strukturyswitch
po wykonaniu tego jednego wybranego przypadku. Bezbreak
program kontynuowałby sprawdzanie kolejnych przypadków (co zwykle nie jest pożądane – z wyjątkiem zaawansowanych zastosowań).
- Jeśli zostanie znaleziony odpowiadający przypadek (
- Jeśli żadna z wartości
case
nie pasuje do wyniku wyrażenia, wykonywany jest blok oznaczony jakodefault
(domyślny). Blokdefault
jest opcjonalny, ale często się go stosuje, by obsłużyć sytuacje nieprzewidziane innymi przypadkami. - Po wykonaniu dopasowanego bloku (lub
default
) następujebreak
, które kończy całą instrukcjęswitch
(ew. zakończenie blokuswitch
jeśli to ostatnia część).
Przykład: załóżmy, że mamy zmienną day
z numerem dnia tygodnia (np. 0 = niedziela, 1 = poniedziałek, …, 6 = sobota) i chcemy przypisać do zmiennej nazwanaDnia
polską nazwę tego dnia tygodnia. Możemy użyć switch
:
let day = 3; // załóżmy, że 0-niedziela, 1-poniedziałek, ..., 6-sobota
let nazwaDnia;
switch(day) {
case 0:
nazwaDnia = "Niedziela";
break;
case 1:
nazwaDnia = "Poniedziałek";
break;
case 2:
nazwaDnia = "Wtorek";
break;
case 3:
nazwaDnia = "Środa";
break;
case 4:
nazwaDnia = "Czwartek";
break;
case 5:
nazwaDnia = "Piątek";
break;
case 6:
nazwaDnia = "Sobota";
break;
default:
nazwaDnia = "Nieznany dzień";
break;
}
console.log("Dzień " + day + " to " + nazwaDnia);
Dla day = 3
powyższy kod znajdzie przypadek case 3
, przypisze zmiennej nazwaDnia
wartość „Środa” i wykona break
, które kończy switch
. Zmienna nazwaDnia
będzie więc zawierać „Środa”, a ostatnia linia wypisze: „Dzień 3 to Środa”. Gdyby zmienna day
miała wartość spoza zakresu 0–6 (np. 7 lub -1), żaden z przypadków nie pasowałby i wykonałby się blok default
, ustawiając nazwaDnia
na „Nieznany dzień”.
Jak widać, switch
bywa czytelniejszy od rozbudowanego łańcucha if...else if...
w sytuacji, gdy porównujemy tę samą zmienną do wielu różnych wartości. Należy pamiętać o umieszczaniu break
po każdym bloku przypadku, aby uniknąć tzw. przechodzenia (fall-through), w którym kod „przelatuje” do kolejnego przypadku. Jeśli celowo chcemy zgrupować kilka wartości, które mają prowadzić do tego samego kodu, można dać kilka case
pod rząd bez break
, a dopiero na końcu wspólny blok kodu i jeden break
. Przykładowo, gdybyśmy traktowali zarówno case 0 jak i 6 (niedziela i sobota) jako „weekend”, moglibyśmy napisać:
switch(day) {
case 0:
case 6:
console.log("Weekend!");
break;
// ... reszta przypadków ...
}
W powyższym fragmencie, dla day = 0 lub day = 6, kod wejdzie w przypadek i ponieważ po case 0 nie ma break
, od razu przejdzie dalej – natrafi na case 6, wykona jego blok (wypisze „Weekend!”) i wyjdzie z switch
. Dla innych wartości day ten fragment zostanie pominięty.
Operator warunkowy ?:
(ternary)
Oprócz instrukcji if
i switch
, w JavaScript istnieje jeszcze tzw. operator warunkowy (zwany też trójargumentowym, ternary operator), zapisywany symbolem ? :
. Nie jest to struktura składniowa jak if
, lecz operator, a zatem pozwala zbudować wyrażenie zwracające pewną wartość w zależności od warunku. Składnia operatora warunkowego jest następująca:
warunek ? wartość_gdy_true : wartość_gdy_false
Działanie: jeśli warunek
jest prawdziwy, całe wyrażenie przyjmuje wartość po znaku ?
(przed dwukropkiem), natomiast jeśli warunek
jest fałszywy – wartość po dwukropku :
. Operator ten wymaga trzech operandów: warunku, wyniku dla true i wyniku dla false – stąd nazwa ternary (trójargumentowy).
Przykład: przypuśćmy, że mamy zmienną liczba
i chcemy przypisać zmiennej parzystosc
tekst „parzysta” lub „nieparzysta” w zależności od tego, czy liczba
jest parzysta. Zamiast używać if...else
, możemy to zrobić w jednej linii z ?:
:
let liczba = 10;
let parzystosc = (liczba % 2 == 0) ? "parzysta" : "nieparzysta";
console.log(parzystosc); // "parzysta"
Tutaj warunkiem jest liczba % 2 == 0
. Jeśli jest on spełniony, parzystosc
otrzyma wartość „parzysta”, w przeciwnym razie „nieparzysta”. Dla liczby 10 wynik warunku to true, więc zmienna parzystosc
będzie miała wartość „parzysta”. Operator ?:
bywa bardzo przydatny do prostych przypisań zależnych od warunku lub do wyrażenia czegoś krótkiego w jednej linijce. Należy jednak unikać zagnieżdżania wielu operatorów ?:
lub umieszczania w nich zbyt skomplikowanego kodu, gdyż może to obniżyć czytelność. W takich wypadkach zwykły if...else
często okazuje się bardziej przejrzysty.
Kontekst logiczny (truthy/falsy): Warto wspomnieć, że w JavaScript warunek w instrukcji if
(albo w operatorze warunkowym) nie musi być bezpośrednio wyrażeniem true
/false
. Interpreter języka próbuje go zinterpretować jako wartość prawdziwą lub fałszywą zgodnie z pewnymi regułami. Na przykład, wartości takie jak 0
, ""
(pusty string), null
, undefined
oraz NaN
są traktowane jako fałszywe (tzw. falsy values), natomiast inne wartości liczbowe (poza zerem), niepuste łańcuchy znaków czy obiekty są traktowane jako prawdziwe (truthy values). Przykładowo, if (5) {...}
zostanie wykonane (bo 5 jest traktowane jak true), zaś if (0) {...}
zostanie pominięte (bo 0 zachowuje się jak false). Mimo istnienia tych zasad, dla czytelności kodu lepiej jest explicite porównywać wartości w warunkach (np. if (x != 0)
zamiast if (x)
w kontekście liczbowym), aby nie polegać zbytnio na pamiętaniu, które wartości są truthy/falsy, szczególnie na początku nauki.
Instrukcje warunkowe odgrywają kluczową rolę w sterowaniu przepływem programu. Dzięki nim program podejmuje decyzje i może wykonywać różne operacje zależnie od danych. Gdy już opanujemy warunki, następnym krokiem jest możliwość wielokrotnego wykonywania pewnych fragmentów kodu – temu służą pętle, które omówimy w kolejnej sekcji.