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
}

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *