Kurs JavaScript i TypeScript · Moduł 5: Zaawansowany JavaScript
Konsola przeglądarki i jej funkcje
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łądJest 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: 3Moż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:
- Kliknij prawym przyciskiem myszy w konsoli
- 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 logowanieconsole.error(),console.warn(),console.info()- różne poziomy komunikatówconsole.table()- przejrzyste wyświetlanie danychconsole.group()- organizacja powiązanych logówconsole.time()iconsole.timeEnd()- mierzenie wydajnościconsole.trace()- diagnozowanie skąd pochodzi wywołanieconsole.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. Które narzędzie w przeglądarce pozwala mierzyć czas wykonania fragmentu kodu JavaScript?