Instrukcje warunkowe pozwalają naszemu kodowi podejmować decyzje. W zależności od spełnienia określonych warunków, możemy kierować przepływ programu w różne strony. W JavaScript mamy kilka rodzajów instrukcji warunkowych:
if
Najprostsza forma która sprawdza warunek i wykonuje kod, jeśli warunek jest prawdziwy.
let score = 75;
if (score > 70) {
console.log("Gratulacje, zdałeś!");
}
Gdy po sprawdzeniu warunku chcemy wykonać tylko jedno działanie, możemy napisać to bez użycia nawiasów klamrowych, tak jak tutaj:
let score = 75;
if (score > 70) console.log("Gratulacje, zdałeś!");
Lecz nie jest to zalecane ze względu na zmniejszoną czytelność kodu
else
Używana z if
pozwala na wykonanie alternatywnego kodu gdy warunek if
nie jest spełniony.
let score = 65;
if (score > 70) {
console.log("Gratulacje, zdałeś!");
} else {
console.log("Niestety, nie zdałeś. Spróbuj ponownie!");
}
else if
Pozwala na sprawdzenie wielu warunków jeden po drugim.
let score = 85;
if (score > 90) {
console.log("Świetnie, ocena 5!");
} else if (score > 80) {
console.log("Dobrze, ocena 4!");
} else if (score > 70) {
console.log("Całkiem nieźle, ocena 3!");
} else {
console.log("Niestety, musisz poprawić wynik.");
}
switch
Alternatywa dla wielokrotnych if...else if...else
, lepiej nadaje się do porównywania tej samej zmiennej z różnymi wartościami.
let day = 2;
switch(day) {
case 1:
console.log("Poniedziałek");
break;
case 2:
console.log("Wtorek");
break;
case 3:
console.log("Środa");
break;
// ...
default:
console.log("Taki dzień nie istnieje!");
}
JavaScript sprawdza warunki w case
i, po znalezieniu pasującego, wykonuje następujący kod. break
sygnalizuje interpreterowi by zakończył działanie w switch
i wyszedł z niego.
Ważne jest, aby pamiętać, że JavaScript stosuje ścisłe porównanie (===) do oceny warunków określonych w każdym case. To oznacza, że zarówno typ wartości, jak i jej wartość muszą być dokładnie takie same, aby warunek został uznany za spełniony.
Grupowanie przypadków
W przypadku gdy kilka warunków wykonuje te same instrukcje, możemy pominąć break:
function season(month) {
let sezon;
switch (month) {
case 12:
case 1:
case 2:
sezon = "zima";
break;
case 3:
case 4:
case 5:
sezon = "wiosna";
break;
case 6:
case 7:
case 8:
sezon = "lato";
break;
case 9:
case 10:
case 11:
sezon = "jesień";
break;
default:
sezon = "nieznany miesiąc";
}
return sezon;
}
console.log(season(1)); // Zwraca "zima"
switch wewnątrz funkcji
W przypadku gdy switch
jest umieszczony w funkcji, możemy użyć return
do natychmiastowego zwrócenia wartości i wyjścia z funkcji, eliminując potrzebę używania break
. To pozwala na bardziej zwięzłe i celowe użycie switch
, ponieważ każdy przypadek (case
) kończy działanie funkcji, zwracając określony wynik.
function results(score) {
switch(true) {
case score >= 90:
return "Świetnie: Ocena 5";
case score >= 80:
return "Dobrze: Ocena 4";
case score >= 70:
return "Zadowalająco: Ocena 3";
case score >= 60:
return "Dopuszczająco: Ocena 2";
default:
return "Niedostatecznie: Ocena 1";
}
}
console.log(results(85)); // Wyświetli "Dobrze: Ocena 4"
Operator trójargumentowy ?:
To skrócona forma instrukcji warunkowej, która pozwala przypisać wartość zmiennej na podstawie spełnienia warunku. Składnia tego operatora wygląda następująco:
warunek ? wyrażenie1 : wyrażenie2;
Przykład użycia:
let score = 85;
let result = score > 75 ? "Zdałeś!" : "Nie zdałeś";
console.log(result);
Przy wszystkich warunkach, należy mieć na uwadze jak JavaScript konwertuje typy
Antywzorce
Nadmierne użycie operatora trójargumentowego
Operator trójargumentowy jest przydatny dla prostych warunków, ale jego nadmierne użycie, szczególnie w zagnieżdżonych strukturach, może uczynić kod trudnym do zrozumienia. Zamiast komplikować logikę:
const accessLevel = user.isAdmin ? 'full' : user.isModerator ? 'partial' : 'none';
Lepszym rozwiązaniem jest użycie zwykłych instrukcji warunkowych if...else
lub wydzielenie logiki do osobnej funkcji, co zwiększa czytelność:
let accessLevel;
if (user.isAdmin) {
accessLevel = 'full';
} else if (user.isModerator) {
accessLevel = 'partial';
} else {
accessLevel = 'none';
}
Piramidy zagłady
Piramida zagłady to problem w programowaniu, gdzie zagnieżdżone instrukcje warunkowe prowadzą do kodu, który jest trudny do odczytania, utrzymania i rozszerzania. Gdy logika decyzyjna opiera się na wielu poziomach zagnieżdżenia, kod staje się podobny do piramidy, co znacząco obniża jego czytelność.
Przykład błędnego kodu:
if (user.role == "admin") {
if (user.isActive) {
if (user.hasPermissions) {
// Akcji dla użytkownikom z dostępem
} else {
// Akcji dla użytkowników bez dostępu
}
} else {
// Akcje dla nieaktywnych userów
}
} else if (user.role == "user") {
if (user.isActive) {
// Akcje dla aktywnego użytkownika
} else {
// Akcje dla nieaktywnego użytkownika
}
}
Zamiast tego, można zastosować wzorce projektowe aby uprościć logikę:
const actions = {
admin: { active: adminActiveAction, inactive: adminInactiveAction },
user: { active: userActiveAction, inactive: userInactiveAction }
};
function executeAction(user) {
const action = actions[user.role][user.isActive ? 'active' : 'inactive'];
action();
}
Ten kod wykorzystuje technikę mapowania do dynamicznego wybierania i wykonania funkcji na podstawie stanu użytkownika (aktywny/nieaktywny) i jego roli (admin/user). Jest to przykład zastosowania wzorca projektowego Strategia, gdzie różne strategie (akcje) są wybierane w zależności od kontekstu (tutaj: rola i status użytkownika). Umożliwia to łatwe rozszerzenie logiki o nowe role lub stany bez zmiany głównej funkcji executeAction
, co sprzyja lepszej organizacji kodu i jego elastyczności.
Magiczne liczby
Używanie bezpośrednich wartości (tzw. magicznych liczb lub stringów) w logice warunkowej może utrudnić zrozumienie kodu. Na przykład:
if (user.status === 2) { // Co oznacza 2?
// Akcja dla zatwierdzonych użytkowników
}
Lepszym podejściem jest zdefiniowanie stałych, które jasno określają, co oznaczają dane wartości, co poprawia czytelność i ułatwia późniejsze modyfikacje:
const USER_STATUS_APPROVED = 2;
if (user.status === USER_STATUS_APPROVED) {
// Akcja dla zatwierdzonych użytkowników
}