W Parku Jurajskim, systemy bezpieczeństwa i protokoły operacyjne muszą nieustannie podejmować decyzje: co zrobić, gdy poziom zasilania spadnie poniżej krytycznego poziomu? Jak zareagować, gdy T-Rex zbliży się do ogrodzenia? Jakie procedury uruchomić w przypadku różnych poziomów zagrożenia?
Podobnie, w JavaScript, instrukcje warunkowe pozwalają na podejmowanie decyzji w kodzie na podstawie określonych warunków. Przyjrzyjmy się trzem głównym typom instrukcji warunkowych: if, else if/else i switch.
Instrukcja
if jest najprostszą formą podejmowania decyzji. Wykonuje blok kodu, jeśli określony warunek jest prawdziwy.1// Podstawowa struktura instrukcji if
2if (warunek) {
3 // Kod do wykonania, gdy warunek jest prawdziwy
4}W praktyce, w Parku Jurajskim, możemy użyć instrukcji
if do sprawdzenia, czy należy uruchomić dodatkowe zabezpieczenia:1// System monitorowania poziomu zasilania ogrodzenia
2let poziomZasilania = 75; // procent
3let poziomKrytyczny = 30; // procent
4
5if (poziomZasilania < poziomKrytyczny) {
6 console.log("UWAGA! Krytyczny poziom zasilania. Uruchomienie generatorów zapasowych.");
7 // Kod aktywujący zapasowe generatory...
8}
9
10// System monitorowania aktywności dinozaurów
11let odległośćTRexaOdOgrodzenia = 50; // metry
12let progBezpieczeństwa = 10; // metry
13
14if (odległośćTRexaOdOgrodzenia <= progBezpieczeństwa) {
15 console.log("ALERT! T-Rex zbliża się do ogrodzenia. Aktywacja dodatkowych zabezpieczeń.");
16 // Kod zwiększający napięcie w ogrodzeniu...
17}Jeśli chcemy wykonać różne działania w zależności od tego, czy warunek jest prawdziwy czy fałszywy, używamy konstrukcji
if...else.1// Struktura if...else
2if (warunek) {
3 // Kod do wykonania, gdy warunek jest prawdziwy
4} else {
5 // Kod do wykonania, gdy warunek jest fałszywy
6}W Parku Jurajskim, taka konstrukcja może być używana do decydowania o otwarciu lub zamknięciu atrakcji:
1// System podejmowania decyzji o dostępności atrakcji
2let pogodaOdpowiednia = true;
3let wskaźnikBezpieczeństwa = 3; // skala 1-5
4let minimalnyPoziomBezpieczeństwa = 4;
5
6if (pogodaOdpowiednia && wskaźnikBezpieczeństwa >= minimalnyPoziomBezpieczeństwa) {
7 console.log("Atrakcja 'Safari z Dinozaurami' jest otwarta dla zwiedzających.");
8 // Kod otwierający bramy, aktywujący kolejkę...
9} else {
10 console.log("Atrakcja 'Safari z Dinozaurami' jest tymczasowo zamknięta ze względów bezpieczeństwa.");
11 // Kod zamykający bramy, informujący personel...
12}Gdy mamy więcej niż dwie możliwe ścieżki działania, możemy użyć konstrukcji
if...else if...else.1// Struktura if...else if...else
2if (warunek1) {
3 // Kod do wykonania, gdy warunek1 jest prawdziwy
4} else if (warunek2) {
5 // Kod do wykonania, gdy warunek1 jest fałszywy, ale warunek2 jest prawdziwy
6} else {
7 // Kod do wykonania, gdy żaden z warunków nie jest prawdziwy
8}W kontekście Parku Jurajskiego, taką konstrukcję można zastosować np. do systemu ostrzegania o różnych poziomach zagrożenia:
1// System ostrzegania o zagrożeniach
2let liczbaDrapieżnikówNaWolności = 0;
3let poziomUszkodzeniaOgrodzenia = 15; // procent
4
5if (liczbaDrapieżnikówNaWolności > 0) {
6 console.log("KOD CZERWONY! Ewakuacja natychmiastowa! Drapieżniki na wolności!");
7 // Kod uruchamiający alarmy, procedury ewakuacyjne...
8} else if (poziomUszkodzeniaOgrodzenia > 30) {
9 console.log("KOD POMARAŃCZOWY! Wysokie ryzyko ucieczki dinozaurów. Przygotować się do ewakuacji.");
10 // Kod przygotowujący park do potencjalnej ewakuacji...
11} else if (poziomUszkodzeniaOgrodzenia > 10) {
12 console.log("KOD ŻÓŁTY! Uszkodzenia ogrodzenia wykryte. Wysłać zespół naprawczy.");
13 // Kod wzywający zespół techniczny...
14} else {
15 console.log("KOD ZIELONY. Wszystkie systemy działają prawidłowo.");
16 // Normalny tryb operacyjny...
17}Możemy również umieszczać instrukcje warunkowe wewnątrz innych instrukcji warunkowych. Takie zagnieżdżone instrukcje if są przydatne, gdy chcemy sprawdzić wiele warunków sekwencyjnie.
1// Przykład zagnieżdżonych instrukcji if
2let statusSystemu = "operacyjny";
3let poziomDostępu = "administrator";
4let kodBezpieczeństwa = "A123";
5
6if (statusSystemu === "operacyjny") {
7 console.log("System działa prawidłowo.");
8
9 if (poziomDostępu === "administrator") {
10 console.log("Dostęp administratora przyznany.");
11
12 if (kodBezpieczeństwa === "A123") {
13 console.log("Dostęp do protokołów bezpieczeństwa przyznany.");
14 // Kod ujawniający tajne protokoły bezpieczeństwa...
15 } else {
16 console.log("Błędny kod bezpieczeństwa.");
17 }
18 } else {
19 console.log("Brak uprawnień administratora.");
20 }
21} else {
22 console.log("System nie działa prawidłowo. Uruchom diagnostykę.");
23}Chociaż zagnieżdżone instrukcje if są czasami konieczne, ich nadmierne użycie może prowadzić do tzw. "piramidy zagłady" (callback hell) lub "kodu drabinkowego", który jest trudny do czytania i utrzymania. W takich przypadkach warto rozważyć refaktoryzację kodu przy użyciu podejścia wczesnego zwrotu (early return) lub instrukcji switch.
Instrukcja
switch jest alternatywą dla wielu instrukcji if...else if...else, szczególnie gdy porównujemy jedną wartość z wieloma możliwymi wartościami.1// Struktura instrukcji switch
2switch (wyrażenie) {
3 case wartość1:
4 // Kod do wykonania, gdy wyrażenie === wartość1
5 break;
6 case wartość2:
7 // Kod do wykonania, gdy wyrażenie === wartość2
8 break;
9 // ... więcej przypadków
10 default:
11 // Kod do wykonania, gdy żaden case nie pasuje
12}W Parku Jurajskim, instrukcja
switch może być używana np. do określania protokołów dla różnych gatunków dinozaurów:1// System protokołów dla różnych gatunków
2let gatunekDinozaura = "Velociraptor";
3
4switch (gatunekDinozaura) {
5 case "Tyranozaur":
6 console.log("Protokół bezpieczeństwa T-REX-01: Maksymalny poziom zabezpieczeń.");
7 console.log("Wymagane podwójne ogrodzenie elektryczne, stały monitoring wideo.");
8 break;
9 case "Velociraptor":
10 console.log("Protokół bezpieczeństwa RAPTOR-02: Wysoki poziom zabezpieczeń.");
11 console.log("Wymagane wzmocnione ogrodzenie, monitoring aktywności w grupie.");
12 break;
13 case "Triceratops":
14 console.log("Protokół bezpieczeństwa HERB-03: Standardowy poziom zabezpieczeń.");
15 console.log("Wymagane podstawowe ogrodzenie, monitoring dobrostanu stada.");
16 break;
17 case "Brachiozaur":
18 console.log("Protokół bezpieczeństwa HERB-04: Niski poziom zabezpieczeń.");
19 console.log("Wymagane oznaczenie terenu, regularne dostawy pożywienia.");
20 break;
21 default:
22 console.log("Nieznany gatunek dinozaura. Zastosuj standardowy protokół bezpieczeństwa.");
23 console.log("Skontaktuj się z działem paleontologii w celu identyfikacji gatunku.");
24}Zauważ, że każdy przypadek
case kończy się instrukcją break. Jest to niezwykle ważne, ponieważ bez break, wykonanie kodu będzie kontynuowane przez wszystkie kolejne przypadki, niezależnie od tego, czy pasują one do wyrażenia, czy nie. Ta właściwość nazywana jest "przenikaniem" (fall-through).1// Przykład bez instrukcji break - "przenikanie"
2let poziomZagrożenia = 2; // skala 1-3
3
4switch (poziomZagrożenia) {
5 case 3:
6 console.log("Uruchom procedurę ewakuacji parku!");
7 // brak break - wykonanie przechodzi do następnego case
8 case 2:
9 console.log("Zamknij wszystkie atrakcje i zgromadź personel.");
10 // brak break - wykonanie przechodzi do następnego case
11 case 1:
12 console.log("Zwiększ częstotliwość monitorowania systemów bezpieczeństwa.");
13 // brak break - wykonanie przechodzi do default
14 default:
15 console.log("Utrzymuj standardowe procedury bezpieczeństwa.");
16}
17
18// Wynik dla poziomZagrożenia = 2:
19// "Zamknij wszystkie atrakcje i zgromadź personel."
20// "Zwiększ częstotliwość monitorowania systemów bezpieczeństwa."
21// "Utrzymuj standardowe procedury bezpieczeństwa."Czasami "przenikanie" może być celowe i użyteczne, ale najczęściej jest wynikiem błędu. Zawsze upewnij się, że rozumiesz i zamierzasz takie zachowanie, jeśli rezygnujesz z instrukcji
break.Jednym z prawomocnych zastosowań "przenikania" jest obsługa wielu przypadków z tym samym kodem:
1// Grupowanie przypadków
2let dzieńTygodnia = "sobota";
3
4switch (dzieńTygodnia) {
5 case "poniedziałek":
6 case "wtorek":
7 case "środa":
8 case "czwartek":
9 case "piątek":
10 console.log("Park Jurajski otwarty od 9:00 do 18:00.");
11 break;
12 case "sobota":
13 case "niedziela":
14 console.log("Park Jurajski otwarty od 8:00 do 20:00 (godziny weekendowe).");
15 break;
16 default:
17 console.log("Nieprawidłowy dzień tygodnia.");
18}Dla prostych warunków, możemy użyć operatora warunkowego (nazywanego też operatorem trójskładnikowym lub ternary operator), który jest bardziej zwięzły niż instrukcja
if...else.1// Struktura operatora warunkowego
2warunek ? wyrażenieGdyPrawda : wyrażenieGdyFałszPrzykład wykorzystania w Parku Jurajskim:
1// Przydzielanie poziomu dostępu
2let jestPracownikiem = true;
3let poziomDostępu = jestPracownikiem ? "Pełny dostęp" : "Dostęp tylko dla zwiedzających";
4
5console.log(poziomDostępu); // "Pełny dostęp"
6
7// Określanie komunikatu o statusie
8let liczbaOdwiedzających = 1500;
9let pojemnośćParku = 2000;
10let statusWejścia = liczbaOdwiedzających < pojemnośćParku
11 ? "Park otwarty - Zapraszamy!"
12 : "Park pełny - Przepraszamy, wstrzymano sprzedaż biletów.";
13
14console.log(statusWejścia); // "Park otwarty - Zapraszamy!"Operator warunkowy może być także zagnieżdżany, choć nadmierne zagnieżdżanie może zmniejszyć czytelność kodu:
1// Zagnieżdżony operator warunkowy
2let gatunekDino = "Triceratops";
3let wiek = 5;
4let obszar = gatunekDino === "Tyranozaur" ? "Sektor T"
5 : gatunekDino === "Velociraptor" ? "Sektor V"
6 : gatunekDino === "Triceratops" ? (wiek < 3 ? "Sektor młodych roślinożerców" : "Sektor dorosłych roślinożerców")
7 : "Sektor ogólny";
8
9console.log(obszar); // "Sektor dorosłych roślinożerców"Jak wspomnieliśmy w poprzednich lekcjach, JavaScript traktuje różne wartości jako "prawdziwe" (truthy) lub "fałszywe" (falsy) w kontekście warunków. Możemy wykorzystać tę właściwość w instrukcjach warunkowych:
1// Sprawdzanie istnienia wartości
2let nazwaDinozaura = ""; // pusty string (falsy)
3let numerIdentyfikacyjny = 0; // zero (falsy)
4let przydzielonyObszar = null; // null (falsy)
5let daneBiometryczne; // undefined (falsy)
6let gatunekZarejestrowany = true; // wartość logiczna true (truthy)
7let notatki = "Agresywny osobnik"; // niepusty string (truthy)
8
9if (nazwaDinozaura) {
10 console.log("Nazwa dinozaura: " + nazwaDinozaura);
11} else {
12 console.log("Dinozaur nie ma przypisanej nazwy."); // to się wykona
13}
14
15if (numerIdentyfikacyjny) {
16 console.log("ID: " + numerIdentyfikacyjny);
17} else {
18 console.log("Brak prawidłowego ID."); // to się wykona
19}
20
21if (gatunekZarejestrowany && notatki) {
22 console.log("Gatunek zarejestrowany. Notatki: " + notatki); // to się wykona
23}Czasami, zamiast zagnieżdżać wiele instrukcji
if, lepiej jest użyć podejścia wczesnego zwrotu, szczególnie w funkcjach. Polega ono na szybkim zwracaniu wyniku, gdy tylko zidentyfikujemy warunek, który na to pozwala.1// Funkcja sprawdzająca, czy dinozaur może być przeniesiony do wybiegu publicznego
2function czyNadajeSięDoWybiegPublicznego(dinozaur) {
3 // Wczesne zwroty dla warunków wykluczających
4 if (dinozaur.poziomAgresji > 3) {
5 return false; // Zbyt agresywny
6 }
7
8 if (dinozaur.wiek < 2) {
9 return false; // Zbyt młody
10 }
11
12 if (dinozaur.choroby.length > 0) {
13 return false; // Ma problemy zdrowotne
14 }
15
16 if (dinozaur.gatunekMięsożerny) {
17 // Dodatkowe warunki dla mięsożerców
18 if (dinozaur.wyszkolony && dinozaur.poziomAgresji <= 2) {
19 return true; // Wyszkolony mięsożerca o niskiej agresji
20 } else {
21 return false; // Niewyszkolony lub zbyt agresywny mięsożerca
22 }
23 }
24
25 // Domyślnie roślinożercy są dopuszczani do wybiegu publicznego
26 return true;
27}
28
29// Przykładowe użycie
30let triceratops = {
31 gatunek: "Triceratops",
32 poziomAgresji: 2,
33 wiek: 5,
34 choroby: [],
35 gatunekMięsożerny: false,
36 wyszkolony: false
37};
38
39let velociraptor = {
40 gatunek: "Velociraptor",
41 poziomAgresji: 4,
42 wiek: 3,
43 choroby: [],
44 gatunekMięsożerny: true,
45 wyszkolony: true
46};
47
48console.log(czyNadajeSięDoWybiegPublicznego(triceratops)); // true
49console.log(czyNadajeSięDoWybiegPublicznego(velociraptor)); // falseInstrukcje warunkowe w JavaScript, podobnie jak systemy decyzyjne w Parku Jurajskim, pozwalają na:
if)if...else, if...else if...else)switch)? :)Wybór odpowiedniej struktury warunkowej zależy od konkretnego przypadku użycia, ale generalnie należy dążyć do:
if...else dla prostych warunków binarnychif...else if...else dla kilku powiązanych warunkówswitch gdy porównujemy jedną wartość z wieloma możliwymi wartościamiPodobnie jak systemy bezpieczeństwa w Parku Jurajskim muszą podejmować właściwe decyzje, aby zapewnić bezpieczeństwo, tak i my jako programiści musimy podejmować właściwe decyzje dotyczące struktury naszego kodu, aby zapewnić jego niezawodność i czytelność.
W następnej lekcji przyjrzymy się pętlom, które pozwalają na wielokrotne wykonywanie kodu - niezbędne np. przy przetwarzaniu danych o wielu dinozaurach jednocześnie.