Kurs JavaScript i TypeScript · Moduł 5: Zaawansowany JavaScript

Konsola przeglądarki i jej funkcje

10 min czytania
W tej lekcji7

Zarządzanie Parkiem Jurajskim nie jest łatwym zadaniem. Gdy pojawiają się problemy z systemem śledzenia dinozaurów lub gdy musimy szybko zdiagnozować, dlaczego protokół blokady nie uruchamia się prawidłowo, kluczową umiejętnością jest debugowanie. Jednym z najważniejszych narzędzi diagnostycznych w JavaScript jest konsola przeglądarki.

W tym ćwiczeniu poznamy narzędzie, które będzie Twoim najlepszym przyjacielem podczas poszukiwania i rozwiązywania problemów - konsolę deweloperską przeglądarki.

Otwieranie konsoli deweloperskiej

Zanim zaczniemy wykorzystywać konsolę, musimy wiedzieć, jak ją otworzyć:

  • Chrome/Edge: <kbd>F12</kbd> lub <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> (Windows/Linux) lub <kbd>Cmd</kbd>+<kbd>Option</kbd>+<kbd>J</kbd> (Mac)
  • Firefox: <kbd>F12</kbd> lub <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> (Windows/Linux) lub <kbd>Cmd</kbd>+<kbd>Option</kbd>+<kbd>K</kbd> (Mac)
  • Safari: <kbd>Cmd</kbd>+<kbd>Option</kbd>+<kbd>C</kbd> (musisz najpierw włączyć narzędzia deweloperskie w ustawieniach)

Po otwarciu zobaczysz kilka zakładek, w tym "Console" (Konsola). To właśnie na niej będziemy się skupiać.

Podstawowe funkcje konsoli

1. console.log() - Twój najlepszy przyjaciel

Najczęściej używaną funkcją konsoli jest console.log(). Służy do wyświetlania wartości w konsoli, co jest niezastąpione podczas debugowania:

1// Wyświetlanie prostych wartości
2console.log("System śledzenia dinozaurów uruchomiony");
3console.log(42); // liczba
4console.log(true); // wartość boolowska
5
6// Wyświetlanie wielu wartości naraz
7const dinosaur = { name: "Rex", type: "T-Rex", status: "contained" };
8console.log("Dane dinozaura:", dinosaur, "Aktualizacja:", new Date());
9
10// Łączenie tekstu (interpolacja)
11const sector = "B7";
12const threat = "wysoki";
13console.log(`Wykryto dinozaura w sektorze ${sector}. Poziom zagrożenia: ${threat}`);

W przypadku naszego systemu Parku Jurajskiego możemy używać console.log() do śledzenia różnych zdarzeń:

1function trackDinosaur(id, location) {
2  console.log(`Śledzenie dinozaura #${id} w lokalizacji ${location}`);
3
4  // Logika śledzenia...
5  const status = checkContainment(id);
6
7  if (status !== "contained") {
8    console.log(`ALERT: Dinozaur #${id} nie jest w wybiegu! Aktualny status: ${status}`);
9  }
10
11  return status;
12}

2. console.error(), console.warn(), console.info()

Oprócz standardowego log, mamy specjalne metody dla różnych poziomów komunikatów:

1// Błędy - zwykle pokazywane na czerwono
2console.error("KRYTYCZNY BŁĄD: Awaria systemu ogrodzeń w sektorze T-Rex!");
3
4// Ostrzeżenia - zwykle pokazywane na żółto
5console.warn("Ostrzeżenie: Poziom naładowania baterii w czujnikach ruchu spada poniżej 20%");
6
7// Informacje - często wyróżnione od zwykłych logów
8console.info("Informacja: Zaplanowano przegląd techniczny systemu na jutro, 8:00");

Ich używanie pomaga wizualnie rozróżnić typy komunikatów w konsoli, co jest szczególnie ważne, gdy mamy do czynienia z dużą ilością logów.

3. console.table() - Przejrzyste wyświetlanie danych tabelarycznych

Gdy mamy do czynienia z tablicami obiektów, console.table() jest niezastąpiony:

1// Tablica dinozaurów w naszym parku
2const dinosaurs = [
3  { id: 1, name: "Rex", species: "T-Rex", danger: 9, location: "Wybieg A" },
4  { id: 2, name: "Blue", species: "Velociraptor", danger: 8, location: "Wybieg B" },
5  { id: 3, name: "Delta", species: "Velociraptor", danger: 8, location: "Wybieg B" },
6  { id: 4, name: "Echo", species: "Velociraptor", danger: 7, location: "Wybieg B" },
7  { id: 5, name: "Trike", species: "Triceratops", danger: 4, location: "Wybieg C" }
8];
9
10// Wyświetla piękną tabelę z danymi
11console.table(dinosaurs);
12
13// Możemy też wybrać tylko niektóre kolumny
14console.table(dinosaurs, ["name", "species", "danger"]);

Jest to szczególnie przydatne przy analizie danych, sprawdzaniu wyników zapytań API czy przeglądaniu konfiguracji.

4. console.group() - Grupowanie logów

Gdy mamy wiele powiązanych logów, możemy je zgrupować dla przejrzystości:

1// Monitorowanie konkretnego dinozaura
2function monitorDinosaur(dinosaur) {
3  console.group(`Monitoring: ${dinosaur.name} (${dinosaur.species})`);
4
5  console.log(`Lokalizacja: ${dinosaur.location}`);
6  console.log(`Poziom zagrożenia: ${dinosaur.danger}/10`);
7
8  const healthStatus = checkHealth(dinosaur.id);
9  console.log(`Stan zdrowia: ${healthStatus.status}`);
10
11  if (healthStatus.issues.length > 0) {
12    console.warn(`Wykryto problemy zdrowotne: ${healthStatus.issues.join(', ')}`);
13  }
14
15  const securityStatus = checkSecurity(dinosaur.location);
16  console.log(`Stan zabezpieczeń: ${securityStatus.status}`);
17
18  if (securityStatus.issues.length > 0) {
19    console.error(`Problemy z zabezpieczeniami: ${securityStatus.issues.join(', ')}`);
20  }
21
22  console.groupEnd();
23
24  return { healthStatus, securityStatus };
25}
26
27// Grupowanie można również zagnieżdżać
28function monitorAllDinosaurs(dinosaurs) {
29  console.group('Monitoring wszystkich dinozaurów');
30
31  dinosaurs.forEach(dino => {
32    monitorDinosaur(dino);
33  });
34
35  console.groupEnd();
36}
37
38monitorAllDinosaurs(dinosaurs);

Grupowanie można również zacząć jako zwinięte, używając console.groupCollapsed(), co jest przydatne przy dużej liczbie grup.

5. console.time() i console.timeEnd() - Mierzenie czasu wykonania

Czasem potrzebujemy wiedzieć, jak długo trwa wykonanie pewnych operacji:

1// Mierzenie czasu ładowania modułu
2console.time('Ładowanie modułu śledzenia');
3
4loadTrackingModule()
5  .then(() => {
6    console.timeEnd('Ładowanie modułu śledzenia');
7    // Wyświetli np.: "Ładowanie modułu śledzenia: 235.41ms"
8  });
9
10// Możemy mieć wiele równoległych timerów
11console.time('Inicjalizacja systemu');
12console.time('Przetwarzanie danych');
13
14initSystem()
15  .then(() => {
16    console.timeEnd('Inicjalizacja systemu');
17    return processData();
18  })
19  .then(() => {
20    console.timeEnd('Przetwarzanie danych');
21  });

Jest to niezwykle przydatne do identyfikacji wąskich gardeł w aplikacji i optymalizacji wydajności.

6. console.trace() - Śledzenie stosu wywołań

Gdy nie wiesz, skąd dokładnie została wywołana funkcja:

1function monitorFenceStatus(sectorId) {
2  console.trace(`Sprawdzanie statusu ogrodzenia w sektorze ${sectorId}`);
3  // Reszta kodu...
4}
5
6function checkAllFences() {
7  const sectors = ['A1', 'B2', 'C3'];
8  sectors.forEach(monitorFenceStatus);
9}
10
11function dailySecurityCheck() {
12  checkAllFences();
13}
14
15dailySecurityCheck();

console.trace() wyświetli pełny stos wywołań funkcji, pokazując dokładną ścieżkę wykonania, co jest nieocenione przy debugowaniu skomplikowanych wywołań.

7. console.assert() - Warunkowe komunikaty debugowania

Sprawdza warunek i wyświetla błąd, gdy warunek jest fałszywy:

1function feedDinosaur(dinosaur, foodAmount) {
2  // Upewniamy się, że ilość jedzenia jest wystarczająca dla danego gatunku
3  console.assert(
4    foodAmount >= getMinimumFoodRequirement(dinosaur.species),
5    `Niewystarczająca ilość jedzenia dla ${dinosaur.name}! ` +
6    `Wymagane minimum: ${getMinimumFoodRequirement(dinosaur.species)}kg, ` +
7    `Dostarczono: ${foodAmount}kg`
8  );
9
10  // Reszta kodu...
11}
12
13feedDinosaur(dinosaurs[0], 5); // Jeśli 5kg to za mało, zobaczymy błąd

Jest to przydatne do wczesnegowykrywania potencjalnych problemów, bez przerywania działania programu.

8. console.count() - Liczenie wywołań

Liczenie, ile razy dana funkcja lub blok kodu został wywołany:

1function checkFenceVoltage(sectorId) {
2  console.count(`Sprawdzenie napięcia w sektorze ${sectorId}`);
3  // Reszta kodu...
4}
5
6// Symulacja regularnego sprawdzania
7setInterval(() => checkFenceVoltage('A1'), 5000);
8setInterval(() => checkFenceVoltage('B2'), 8000);

Po każdym wywołaniu zobaczymy w konsoli coś w rodzaju:

1Sprawdzenie napięcia w sektorze A1: 1
2Sprawdzenie napięcia w sektorze A1: 2
3Sprawdzenie napięcia w sektorze B2: 1
4Sprawdzenie napięcia w sektorze A1: 3

Możemy zresetować licznik używając console.countReset('nazwa').

9. console.dir() - Wyświetlanie właściwości obiektu

Gdy chcemy zobaczyć pełną strukturę obiektu:

1const parkSystem = {
2  name: "Jurassic Park",
3  sectors: {
4    A: { dinosaurs: [/*...*/], status: "secure" },
5    B: { dinosaurs: [/*...*/], status: "alert" },
6    //
7  },
8  security: {
9    fences: { status: "online", voltage: 10000 },
10    cameras: { operational: 45, offline: 3 },
11    //
12  },
13  //
14};
15
16// Wyświetla interaktywną, rozwijaną strukturę obiektu
17console.dir(parkSystem);

Ta funkcja jest szczególnie przydatna dla złożonych obiektów, gdyż pozwala na przeglądanie zagnieżdżonych właściwości.

10. Formatowanie komunikatów w konsoli

Konsola obsługuje również podstawowe formatowanie za pomocą specyfikatorów:

1// Formatowanie tekstu z różnymi stylami CSS
2console.log(
3  "%cUWAGA! %cPoziom zagrożenia krytyczny %cin sektorze B!",
4  "color: red; font-size: 20px; font-weight: bold;",
5  "color: orange; font-size: 16px;",
6  "color: black; font-weight: bold;"
7);
8
9// Wyświetlanie zmiennych w komunikacie
10console.log("Dinozaur %s ma poziom zagrożenia %d", "Rex", 9);

Zaawansowane funkcje konsoli

1. Filtrowanie komunikatów

Większość konsoli przeglądarek pozwala na filtrowanie wyświetlanych komunikatów. Możemy filtrować według:

  • Poziomu (Error, Warning, Info, Log)
  • Tekstu (wpisując frazę do wyszukania)
  • Źródła (np. tylko z określonego pliku)

Jest to niezwykle przydatne, gdy mamy do czynienia z dużą ilością logów.

2. Zapisywanie do pliku

Komunikaty z konsoli możemy zazwyczaj zapisać do pliku, co jest przydatne do analizy logów:

  1. Kliknij prawym przyciskiem myszy w konsoli
  2. Wybierz "Save as..." lub "Zapisz jako..."

3. Czyszczenie konsoli

Konsolę można wyczyścić na kilka sposobów:

  • Kliknięcie ikony przekreślonego koła w konsoli
  • Naciśnięcie <kbd>Ctrl</kbd>+<kbd>L</kbd> (gdy konsola jest aktywna)
  • Użycie kodu: console.clear()

4. Konsola jako środowisko REPL

Konsola przeglądarki działa również jako REPL (Read-Eval-Print Loop), co oznacza, że możemy bezpośrednio wykonywać w niej kod JavaScript:

1// Bezpośrednio w konsoli
2const dinos = [{name: "Rex"}, {name: "Blue"}];
3dinos.filter(d => d.name === "Blue");
4
5// Definiowanie funkcji
6function alertSecurity(message) {
7  return `[SECURITY ALERT] ${message} - ${new Date().toISOString()}`;
8}
9
10// Używanie tej funkcji
11alertSecurity("Naruszenie ogrodzenia w sektorze C2");

Jest to niezwykle przydatne do testowania małych fragmentów kodu czy debugowania bez modyfikowania kodu źródłowego.

Praktyczna implementacja w naszym systemie Parku Jurajskiego

Stwórzmy praktyczną implementację systemu logowania dla naszego Parku Jurajskiego, który wykorzysta różne funkcje konsoli:

1// Logger dla systemu Parku Jurajskiego
2class JurassicLogger {
3  constructor(moduleName) {
4    this.moduleName = moduleName;
5    this.logCount = 0;
6    this.errorCount = 0;
7    this.warnCount = 0;
8  }
9
10  log(...args) {
11    this.logCount++;
12    console.log(`[${this.moduleName}] `, ...args);
13  }
14
15  error(...args) {
16    this.errorCount++;
17    console.error(`[${this.moduleName}] ERROR:`, ...args);
18  }
19
20  warn(...args) {
21    this.warnCount++;
22    console.warn(`[${this.moduleName}] WARNING:`, ...args);
23  }
24
25  info(...args) {
26    console.info(`[${this.moduleName}] INFO:`, ...args);
27  }
28
29  startGroup(label) {
30    console.group(`[${this.moduleName}] ${label}`);
31  }
32
33  endGroup() {
34    console.groupEnd();
35  }
36
37  startTimer(label) {
38    console.time(`[${this.moduleName}] ${label}`);
39  }
40
41  endTimer(label) {
42    console.timeEnd(`[${this.moduleName}] ${label}`);
43  }
44
45  table(data, columns) {
46    console.log(`[${this.moduleName}] Dane tabelaryczne:`);
47    console.table(data, columns);
48  }
49
50  getStats() {
51    return {
52      moduleName: this.moduleName,
53      logs: this.logCount,
54      errors: this.errorCount,
55      warnings: this.warnCount
56    };
57  }
58
59  trace(message) {
60    console.log(`[${this.moduleName}] TRACE: ${message}`);
61    console.trace();
62  }
63
64  assert(condition, message) {
65    console.assert(condition, `[${this.moduleName}] Assertion failed: ${message}`);
66  }
67
68  // Formatowanie specjalne dla alertów bezpieczeństwa
69  securityAlert(message, level = 'warning') {
70    const styles = {
71      warning: "background: #FFA500; color: black; padding: 2px 5px; border-radius: 3px;",
72      critical: "background: #FF0000; color: white; padding: 2px 5px; border-radius: 3px; font-weight: bold;",
73      info: "background: #0066FF; color: white; padding: 2px 5px; border-radius: 3px;"
74    };
75
76    console.log(
77      `%c[${this.moduleName}] SECURITY ALERT %c${message}`,
78      styles[level] || styles.warning,
79      "color: black;"
80    );
81  }
82}
83
84// Przykład użycia
85const securityLogger = new JurassicLogger('ParkSecurity');
86const dinosaurLogger = new JurassicLogger('DinosaurTracker');
87const systemLogger = new JurassicLogger('MainSystem');
88
89// Inicjalizacja systemu
90systemLogger.startTimer('Inicjalizacja systemu');
91systemLogger.log('Rozpoczynanie inicjalizacji systemów Parku Jurajskiego...');
92
93// Symulacja inicjalizacji podsystemów
94setTimeout(() => {
95  systemLogger.info('Podsystemy uruchomione');
96  systemLogger.endTimer('Inicjalizacja systemu');
97
98  // Informacje o dinozaurach
99  const dinoData = [
100    { id: 'TRX-01', name: 'Rex', species: 'T-Rex', status: 'contained', healthLevel: 92 },
101    { id: 'VEL-01', name: 'Blue', species: 'Velociraptor', status: 'contained', healthLevel: 87 },
102    { id: 'VEL-02', name: 'Delta', species: 'Velociraptor', status: 'sedated', healthLevel: 65 },
103    { id: 'TRI-01', name: 'Sarah', species: 'Triceratops', status: 'contained', healthLevel: 95 }
104  ];
105
106  dinosaurLogger.startGroup('Raport statusu dinozaurów');
107  dinosaurLogger.table(dinoData);
108
109  // Sprawdzanie stanu zdrowia dinozaurów
110  dinoData.forEach(dino => {
111    dinosaurLogger.startGroup(`Dinozaur: ${dino.name}`);
112
113    if (dino.healthLevel < 70) {
114      dinosaurLogger.warn(`Poziom zdrowia dinozaura ${dino.name} jest niski: ${dino.healthLevel}%`);
115    } else {
116      dinosaurLogger.log(`Stan zdrowia: ${dino.healthLevel}%`);
117    }
118
119    if (dino.status !== 'contained') {
120      dinosaurLogger.error(`Dinozaur ${dino.name} nie jest w wybiegu! Status: ${dino.status}`);
121      securityLogger.securityAlert(`Dinozaur ${dino.name} (${dino.species}) ma status: ${dino.status}`, 'critical');
122    }
123
124    dinosaurLogger.endGroup();
125  });
126
127  dinosaurLogger.endGroup();
128
129  // Sprawdzanie systemów bezpieczeństwa
130  securityLogger.startGroup('Systemy bezpieczeństwa');
131
132  const fenceStatus = { sector: 'B', voltage: 9800, status: 'active' };
133  securityLogger.log(`Status ogrodzenia w sektorze ${fenceStatus.sector}: ${fenceStatus.status}`);
134  securityLogger.assert(
135    fenceStatus.voltage >= 10000,
136    `Napięcie ogrodzenia w sektorze ${fenceStatus.sector} jest zbyt niskie: ${fenceStatus.voltage}V (min. 10000V)`
137  );
138
139  // Symulacja naruszenia bezpieczeństwa
140  if (Math.random() > 0.7) {
141    securityLogger.trace('Wykryto nieautoryzowany dostęp do panelu sterowania');
142    securityLogger.securityAlert('Wykryto nieautoryzowany dostęp do systemów kontroli!', 'critical');
143  }
144
145  securityLogger.endGroup();
146
147  // Wyświetlanie statystyk logów
148  systemLogger.startGroup('Statystyki logów');
149  console.table([
150    securityLogger.getStats(),
151    dinosaurLogger.getStats(),
152    systemLogger.getStats()
153  ]);
154  systemLogger.endGroup();
155
156}, 2000);

Integracja z frameworkami

Nowoczesne frameworki jak React czy Vue mają własne integracje z konsolą, które dostarczają dodatkowych informacji debugujących:

React DevTools

React DevTools dodaje do konsoli przeglądarki specjalne narzędzia do inspekcji komponentów React, stanu, propów i drzewa komponentów. To niezastąpione narzędzie dla każdego dewelopera React.

Vue DevTools

Podobnie Vue ma własne narzędzia deweloperskie, które pozwalają na inspekcję komponentów, stanu Vuex i innych aspektów aplikacji Vue.

Logowanie produkcyjne i deweloperskie

W rzeczywistych aplikacjach warto rozdzielić logowanie deweloperskie od produkcyjnego:

1// logger.js
2class Logger {
3  constructor(isProduction = process.env.NODE_ENV === 'production') {
4    this.isProduction = isProduction;
5  }
6
7  log(...args) {
8    if (!this.isProduction) {
9      console.log(...args);
10    }
11  }
12
13  // W przypadku błędów krytycznych, logujemy nawet na produkcji
14  error(...args) {
15    console.error(...args);
16
17    if (this.isProduction) {
18      // Na produkcji możemy wysłać błędy do usługi monitorowania
19      this.sendToErrorMonitoring(args);
20    }
21  }
22
23  // ...inne metody
24
25  sendToErrorMonitoring(errorData) {
26    // Implementacja wysyłania do Sentry, LogRocket itp.
27  }
28}
29
30export default new Logger();

Podsumowanie

Konsola przeglądarki to potężne narzędzie, które znacznie ułatwia debugowanie i monitorowanie aplikacji JavaScript. W kontekście naszego Parku Jurajskiego, dobre praktyki logowania mogą być różnicą między sprawnie działającym parkiem a... cóż, scenariuszem znanym z filmów!

Najważniejsze funkcje do zapamiętania:

  • console.log() - podstawowe logowanie
  • console.error(), console.warn(), console.info() - różne poziomy komunikatów
  • console.table() - przejrzyste wyświetlanie danych
  • console.group() - organizacja powiązanych logów
  • console.time() i console.timeEnd() - mierzenie wydajności
  • console.trace() - diagnozowanie skąd pochodzi wywołanie
  • console.assert() - warunkowe komunikaty debugowania

Pamiętaj, aby regularnie używać konsoli podczas tworzenia aplikacji - pomoże Ci to szybciej wykrywać i naprawiać błędy, zanim dinozaury znajdą lukę w Twoim kodzie!

Kod do tej lekcji: main.js
1// Re-exportowanie i agregacja modułów - Park Jurajski
2// Tworzenie "index" modułów dla łatwiejszego importowania
3
4console.log("Re-exportowanie i Agregacja Modułów");
5console.log("Organizacja struktury modułów\n");
6
7// ===========================================
8// MODUŁY BAZOWE
9// ===========================================
10
11// === types/DinosaurTypes.js ===
12const DinosaurTypes = {
13  CARNIVORE: 'carnivore',
14  HERBIVORE: 'herbivore',
15  OMNIVORE: 'omnivore'
16};
17
18const DangerLevels = {
19  LOW: 1,
20  MEDIUM: 5,
21  HIGH: 7,
22  CRITICAL: 9
23};
24
25// === models/Dinosaur.js ===
26class Dinosaur {
27  constructor(name, species, type, dangerLevel) {
28    this.name = name;
29    this.species = species;
30    this.type = type;
31    this.dangerLevel = dangerLevel;
32    this.health = 100;
33    this.id = Math.random().toString(36).substr(2, 9);
34  }
35
36  getInfo() {
37    return `${this.name} (${this.species}) - Danger: ${this.dangerLevel}/10`;
38  }
39}
40
41// === models/Enclosure.js ===
42class Enclosure {
43  constructor(id, name, capacity) {
44    this.id = id;
45    this.name = name;
46    this.capacity = capacity;
47    this.dinosaurs = [];
48  }
49
50  addDinosaur(dinosaur) {
51    if (this.dinosaurs.length >= this.capacity) {
52      throw new Error('Enclosure is full');
53    }
54    this.dinosaurs.push(dinosaur);
55  }
56
57  getStatus() {
58    return `${this.name}: ${this.dinosaurs.length}/${this.capacity} dinosaurs`;
59  }
60}
61
62// === models/Visitor.js ===
63class Visitor {
64  constructor(name, age, ticketType) {
65    this.name = name;
66    this.age = age;
67    this.ticketType = ticketType;
68    this.id = Math.random().toString(36).substr(2, 9);
69  }
70
71  getDetails() {
72    return `${this.name}, ${this.age} years old (${this.ticketType} ticket)`;
73  }
74}
75
76// === utils/validators.js ===
77function validateDinosaur(data) {
78  const { name, species, type, dangerLevel } = data;
79  const errors = [];
80
81  if (!name || typeof name !== 'string') errors.push('Invalid name');
82  if (!species || typeof species !== 'string') errors.push('Invalid species');
83  if (!Object.values(DinosaurTypes).includes(type)) errors.push('Invalid type');
84  if (dangerLevel < 1 || dangerLevel > 10) errors.push('Danger level must be 1-10');
85
86  return { valid: errors.length === 0, errors };
87}
88
89function validateEnclosure(data) {
90  const { id, name, capacity } = data;
91  const errors = [];
92
93  if (!id || typeof id !== 'string') errors.push('Invalid id');
94  if (!name || typeof name !== 'string') errors.push('Invalid name');
95  if (!capacity || capacity < 1) errors.push('Capacity must be at least 1');
96
97  return { valid: errors.length === 0, errors };
98}
99
100// === utils/formatters.js ===
101function formatDinosaurReport(dinosaur) {
102  return {
103    id: dinosaur.id,
104    name: dinosaur.name,
105    species: dinosaur.species,
106    type: dinosaur.type,
107    dangerLevel: dinosaur.dangerLevel,
108    health: `${dinosaur.health}%`,
109    status: dinosaur.health > 70 ? 'Good' : 'Needs attention'
110  };
111}
112
113function formatEnclosureReport(enclosure) {
114  return {
115    id: enclosure.id,
116    name: enclosure.name,
117    occupancy: `${enclosure.dinosaurs.length}/${enclosure.capacity}`,
118    dinosaurs: enclosure.dinosaurs.map(d => d.name),
119    status: enclosure.dinosaurs.length >= enclosure.capacity ? 'Full' : 'Available'
120  };
121}
122
123// ===========================================
124// MODUŁY AGREGUJĄCE (BARREL EXPORTS)
125// ===========================================
126
127// === models/index.js - Agregacja wszystkich modeli ===
128// Re-export wszystkich modeli z jednego miejsca
129const ModelsModule = {
130  Dinosaur,
131  Enclosure,
132  Visitor
133};
134
135console.log("Models Module:");
136console.log("  - Dinosaur");
137console.log("  - Enclosure");
138console.log("  - Visitor\n");
139
140// === types/index.js - Agregacja typów ===
141const TypesModule = {
142  DinosaurTypes,
143  DangerLevels
144};
145
146console.log("Types Module:");
147console.log("  - DinosaurTypes");
148console.log("  - DangerLevels\n");
149
150// === utils/index.js - Agregacja utilities ===
151const UtilsModule = {
152  // validators
153  validateDinosaur,
154  validateEnclosure,
155  // formatters
156  formatDinosaurReport,
157  formatEnclosureReport
158};
159
160console.log("Utils Module:");
161console.log("  - validateDinosaur");
162console.log("  - validateEnclosure");
163console.log("  - formatDinosaurReport");
164console.log("  - formatEnclosureReport\n");
165
166// === index.js - GŁÓWNY MODUŁ AGREGUJĄCY ===
167// Re-export wszystkiego z podmodułów
168const JurassicParkSDK = {
169  // Models
170  ...ModelsModule,
171  // Types
172  ...TypesModule,
173  // Utils
174  ...UtilsModule
175};
176
177console.log("Main SDK Module (All exports):");
178console.log("  All models");
179console.log("  All types");
180console.log("  All utilities\n");
181
182// ===========================================
183// DEMONSTRACJA UŻYCIA
184// ===========================================
185
186console.log("=== DEMONSTRACJA RE-EXPORTOWANIA ===\n");
187
188// Zamiast importować z wielu miejsc:
189console.log("BEZ re-exportów (wiele importów):");
190console.log("import { Dinosaur } from './models/Dinosaur.js';");
191console.log("import { Enclosure } from './models/Enclosure.js';");
192console.log("import { DinosaurTypes } from './types/DinosaurTypes.js';");
193console.log("import { validateDinosaur } from './utils/validators.js';");
194console.log("import { formatDinosaurReport } from './utils/formatters.js';\n");
195
196// Możemy importować wszystko z jednego miejsca:
197console.log("Z re-exportami (jeden import):");
198console.log("import {");
199console.log("  Dinosaur, Enclosure,");
200console.log("  DinosaurTypes,");
201console.log("  validateDinosaur, formatDinosaurReport");
202console.log("} from './index.js';\n");
203
204console.log("=== PRAKTYCZNE UŻYCIE ===\n");
205
206// Tworzenie dinozaura
207const dinoData = {
208  name: 'Rexy',
209  species: 'Tyrannosaurus Rex',
210  type: JurassicParkSDK.DinosaurTypes.CARNIVORE,
211  dangerLevel: JurassicParkSDK.DangerLevels.CRITICAL
212};
213
214console.log("1. Walidacja danych dinozaura:");
215const validation = JurassicParkSDK.validateDinosaur(dinoData);
216console.log(`   Valid: ${validation.valid}`);
217
218if (validation.valid) {
219  const trex = new JurassicParkSDK.Dinosaur(
220    dinoData.name,
221    dinoData.species,
222    dinoData.type,
223    dinoData.dangerLevel
224  );
225
226  console.log(`\n2. Utworzono dinozaura: ${trex.getInfo()}`);
227
228  const report = JurassicParkSDK.formatDinosaurReport(trex);
229  console.log("\n3. Raport dinozaura:");
230  console.log(JSON.stringify(report, null, 2));
231}
232
233// Tworzenie wybiegu
234console.log("\n4. Tworzenie wybiegu:");
235const enclosureData = {
236  id: 'ENC-001',
237  name: 'T-Rex Paddock',
238  capacity: 2
239};
240
241const encValidation = JurassicParkSDK.validateEnclosure(enclosureData);
242console.log(`   Valid: ${encValidation.valid}`);
243
244if (encValidation.valid) {
245  const paddock = new JurassicParkSDK.Enclosure(
246    enclosureData.id,
247    enclosureData.name,
248    enclosureData.capacity
249  );
250
251  const trex = new JurassicParkSDK.Dinosaur(
252    'Rexy',
253    'T-Rex',
254    JurassicParkSDK.DinosaurTypes.CARNIVORE,
255    9
256  );
257
258  paddock.addDinosaur(trex);
259
260  const encReport = JurassicParkSDK.formatEnclosureReport(paddock);
261  console.log("\n5. Raport wybiegu:");
262  console.log(JSON.stringify(encReport, null, 2));
263}
264
265console.log("\n=== ZALETY RE-EXPORTOWANIA ===\n");
266
267console.log("Uproszczone importy:");
268console.log("   - Jeden import zamiast wielu");
269console.log("   - Czystszy kod\n");
270
271console.log("Lepsze DX (Developer Experience):");
272console.log("   - Łatwiejsze odkrywanie API");
273console.log("   - Intuicyjna struktura\n");
274
275console.log("Łatwiejsze refaktoryzowanie:");
276console.log("   - Zmiany wewnętrznej struktury nie wpływają na użytkowników");
277console.log("   - Publiczne API pozostaje stabilne\n");
278
279console.log("Tree Shaking:");
280console.log("   - Bundlery potrafią usunąć nieużywany kod");
281console.log("   - Mniejszy rozmiar bundla\n");
282
283console.log("=== PRZYKŁADOWE WZORCE ===\n");
284
285console.log("// Podstawowy re-export");
286console.log("export { Dinosaur } from './Dinosaur.js';\n");
287
288console.log("// Re-export z aliasem");
289console.log("export { Dinosaur as Dino } from './Dinosaur.js';\n");
290
291console.log("// Re-export wszystkiego");
292console.log("export * from './models.js';\n");
293
294console.log("// Re-export z agregacją");
295console.log("export { Dinosaur } from './Dinosaur.js';");
296console.log("export { Enclosure } from './Enclosure.js';");
297console.log("export { Visitor } from './Visitor.js';\n");
298
299console.log("// Mixed export (default + named)");
300console.log("export { default as Dinosaur, DinosaurTypes } from './Dinosaur.js';\n");
301
302console.log("Demonstracja zakończona!");

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Które narzędzie w przeglądarce pozwala mierzyć czas wykonania fragmentu kodu JavaScript?

Przydatne artykuły