Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Typy błędów w JavaScript

W Parku Jurajskim, klasyfikacja dinozaurów jest kluczowa dla bezpieczeństwa - musisz wiedzieć, czy masz do czynienia z łagodnym Brachiozaurem czy niebezpiecznym Velociraptorem. Podobnie w JavaScript, rozpoznawanie różnych typów błędów pomaga skutecznie diagnozować i rozwiązywać problemy w kodzie.

Dr. Ian Malcolm powiedziałby: "Błędy... uh... znajdą sposób." I rzeczywiście, nawet w najbardziej starannie napisanym kodzie błędy mogą się pojawić. Dlatego zrozumienie ich typów jest tak ważne.

Błędy składniowe (SyntaxError)

SyntaxError to najbardziej podstawowy typ błędu - występuje, gdy kod zawiera konstrukcję naruszającą zasady składniowe języka JavaScript. To jak próba komunikacji z dinozaurem w niewłaściwym języku - nie zadziała!

1// Przykłady błędów składniowych
2function checkDinosaurEnclosure( {  // Brak zamknięcia nawiasu
3  return isSecure;
4}
5
6const velociraptorCount = 3;
7if (velociraptorCount > 2) {
8  console.log("Zbyt wiele raptorów!") // Brak średnika (może być akceptowalne w niektórych kontekstach)
9} else {
10  console.log("Poziom bezpieczeństwa akceptowalny");
11}

JavaScript zgłosi SyntaxError natychmiast podczas analizy kodu, jeszcze przed jego wykonaniem. Taki błąd całkowicie uniemożliwia uruchomienie programu.

Błędy referencji (ReferenceError)

ReferenceError pojawia się, gdy próbujesz uzyskać dostęp do zmiennej lub funkcji, która nie istnieje lub jest niedostępna w bieżącym zakresie. To jak szukanie dinozaura, który uciekł z wybiegu - nie ma go tam, gdzie powinien być!

1// Przykłady ReferenceError
2function alertSecurityTeam() {
3  // tyrannosaurus nie jest zdefiniowany w tym zakresie
4  if (tyrannosaurus.isLoose) {
5    sendEmergencyAlert();
6  }
7}
8
9// Użycie zmiennej przed jej deklaracją
10console.log(securityCode); // ReferenceError
11const securityCode = "1234";

Błędy typu (TypeError)

TypeError występuje, gdy operacja jest wykonywana na wartości niewłaściwego typu, lub gdy próbujesz wywołać właściwość lub metodę, która nie istnieje. To jak próba traktowania roślinożernego Triceratopsa jak drapieżnika.

1// Przykłady TypeError
2const dinosaurSpecies = ["Tyrannosaurus", "Velociraptor", "Triceratops"];
3
4// Próba wywołania metody na nieprawidłowym typie
5dinosaurSpecies.toUpperCase(); // TypeError: dinosaurSpecies.toUpperCase is not a function
6
7// Próba dostępu do właściwości undefined
8const securitySystem = null;
9console.log(securitySystem.isActive); // TypeError: Cannot read property 'isActive' of null
10
11// Próba wywołania wartości, która nie jest funkcją
12const dinoCount = 5;
13dinoCount(); // TypeError: dinoCount is not a function

Błędy zakresu (RangeError)

RangeError pojawia się, gdy wartość numeryczna jest poza dopuszczalnym zakresem. To jak próba utrzymania więcej dinozaurów w zagrodzie, niż może ona bezpiecznie pomieścić.

1// Przykłady RangeError
2function setDinosaurFeedingSchedule(intervalMs) {
3  // Przekazanie negatywnej wartości do setTimeout spowoduje RangeError
4  setTimeout(feedDinosaurs, intervalMs);
5}
6
7setDinosaurFeedingSchedule(-1000); // RangeError
8
9// Inny przykład - przekroczenie maksymalnej głębokości rekurencji
10function countdownToParkopenning(n) {
11  console.log(n);
12  // Brak warunku bazowego powoduje RangeError: Maximum call stack size exceeded
13  countdownToParkopenning(n - 1);
14}
15
16countdownToParkopenning(10);

Błędy URI (URIError)

URIError występuje, gdy niepoprawne parametry są przekazywane do funkcji kodujących lub dekodujących URI. To rzadszy typ błędu, ale może wystąpić np. przy przetwarzaniu danych z API.

1// Przykład URIError
2try {
3  // Próba dekodowania nieprawidłowej sekwencji URI
4  decodeURIComponent('%'); // URIError: Invalid URI
5} catch (error) {
6  console.error("Błąd podczas dekodowania identyfikatora wybiegu:", error.message);
7}

Błędy ewaluacji (EvalError)

EvalError był historycznie zgłaszany dla problemów związanych z funkcją

eval()
, ale we współczesnym JavaScript jest rzadko używany, podobnie jak funkcja
eval()
powinna być rzadko używana ze względów bezpieczeństwa.

Błędy agregacji (AggregateError)

AggregateError to nowszy typ błędu wprowadzony w ES2020, który grupuje wiele błędów w jeden. Jest używany np. przez

Promise.any()
gdy wszystkie obietnice są odrzucone.

1// Przykład AggregateError
2const dinosaurHealthChecks = [
3  Promise.reject(new Error("Raptor 1: Podwyższona temperatura")),
4  Promise.reject(new Error("Raptor 2: Nieprawidłowe parametry krwi")),
5  Promise.reject(new Error("Raptor 3: Odmowa współpracy"))
6];
7
8Promise.any(dinosaurHealthChecks).catch(errors => {
9  console.log(errors instanceof AggregateError); // true
10  console.log(errors.message); // "All promises were rejected"
11  console.log(errors.errors); // Tablica zawierająca wszystkie błędy
12});

Błędy internacjonalizacji (InternalError)

InternalError jest zgłaszany, gdy błąd wewnętrzny występuje w silniku JavaScript, np. zbyt duża rekurencja. Nie jest to część specyfikacji ECMA, ale jest dostępny w niektórych implementacjach (np. Firefox).

Tworzenie własnych typów błędów

Możemy tworzyć własne, spersonalizowane błędy, rozszerzając klasę Error. W Parku Jurajskim mogłoby to być użyteczne dla specyficznych problemów związanych z zarządzaniem parkiem.

1// Własna klasa błędu dla problemów z dinozaurami
2class DinosaurEscapeError extends Error {
3  constructor(species, location, message) {
4    super(message);
5    this.name = "DinosaurEscapeError";
6    this.species = species;
7    this.location = location;
8    this.timestamp = new Date();
9  }
10}
11
12function checkEnclosure(enclosureData) {
13  if (!enclosureData.isSecure && enclosureData.containsPredators) {
14    throw new DinosaurEscapeError(
15      enclosureData.species,
16      enclosureData.sector,
17      `NIEBEZPIECZEŃSTWO! ${enclosureData.species} wydostał się z wybiegu w sektorze ${enclosureData.sector}!`
18    );
19  }
20}
21
22try {
23  checkEnclosure({
24    species: "Velociraptor",
25    sector: "B4",
26    isSecure: false,
27    containsPredators: true
28  });
29} catch (error) {
30  if (error instanceof DinosaurEscapeError) {
31    console.error(`${error.name}: ${error.message}`);
32    console.error(`Gatunek: ${error.species}, Lokalizacja: ${error.location}`);
33    console.error(`Czas zdarzenia: ${error.timestamp}`);
34
35    // Uruchom procedury bezpieczeństwa
36    activateEmergencyProtocols(error.location);
37    evacuateVisitors(error.location);
38    alertSecurityTeam(error);
39  }
40}

Identyfikacja typów błędów

Aby skutecznie obsługiwać błędy, musimy umieć je identyfikować. W bloku catch możemy sprawdzić typ błędu za pomocą operatora instanceof lub właściwości name.

1try {
2  // Kod, który może generować różne typy błędów
3  const parkSystems = null;
4  console.log(parkSystems.securityStatus); // TypeError
5} catch (error) {
6  if (error instanceof TypeError) {
7    console.error("Błąd typu:", error.message);
8    // Odzyskiwanie po błędzie typu
9    initializeParkSystems();
10  } else if (error instanceof ReferenceError) {
11    console.error("Błąd referencji:", error.message);
12    // Odzyskiwanie po błędzie referencji
13  } else {
14    console.error("Nieznany błąd:", error.message);
15    // Ogólna procedura odzyskiwania
16  }
17}

Właściwości obiektów błędów

Każdy obiekt błędu w JavaScript ma standardowe właściwości:

  1. name: Nazwa typu błędu (np. "TypeError", "SyntaxError")
  2. message: Opis błędu
  3. stack: Ślad stosu (informacja gdzie w kodzie wystąpił błąd)
1try {
2  const securityCameras = undefined;
3  securityCameras.forEach(camera => camera.activate());
4} catch (error) {
5  console.error("Nazwa błędu:", error.name); // "TypeError"
6  console.error("Wiadomość:", error.message); // "Cannot read property 'forEach' of undefined"
7  console.error("Stos wywołań:", error.stack); // Pełny ślad stosu z informacją o linii kodu
8}

Błędy asynchroniczne

Obsługa błędów w kodzie asynchronicznym wymaga specjalnego podejścia. W przypadku obietnic (Promises) używamy metody

catch()
lub bloku
catch
w konstrukcji
async/await
.

1// Obsługa błędów w obietnicach
2fetchDinosaurData()
3  .then(data => processDinosaurData(data))
4  .catch(error => {
5    console.error("Błąd podczas pobierania danych o dinozaurach:", error);
6    return getBackupDinosaurData(); // Plan awaryjny
7  });
8
9// Obsługa błędów w async/await
10async function monitorDinosaurs() {
11  try {
12    const data = await fetchDinosaurData();
13    processDinosaurData(data);
14  } catch (error) {
15    console.error("Błąd monitorowania:", error);
16
17    // Różne procedury odzyskiwania w zależności od błędu
18    if (error instanceof NetworkError) {
19      await switchToOfflineMode();
20    } else if (error instanceof AuthenticationError) {
21      await refreshSecurityCredentials();
22      return monitorDinosaurs(); // Spróbuj ponownie
23    } else {
24      notifyAdministrator(error);
25    }
26  }
27}

Wnioski

Jak powiedział Dr. Alan Grant: "Najlepszą obroną jest wiedza". Rozumienie różnych typów błędów w JavaScript pozwala ci lepiej diagnozować problemy, pisać bardziej odporne aplikacje i skuteczniej obsługiwać nieoczekiwane sytuacje - zarówno w Parku Jurajskim, jak i w twoim kodzie.

W następnym ćwiczeniu przyjrzymy się dokładniej jak zgłaszać własne błędy za pomocą instrukcji

throw
oraz jak obsługiwać błędy za pomocą bloku
try...catch...finally
- niezbędnych narzędzi dla każdego programisty, podobnie jak solidna klatka jest niezbędna dla każdego tresera raptorów!

Przejdź do CodeWorlds