Kurs JavaScript i TypeScript · Moduł 2: Funkcje, tablice i obiekty
Podstawowe metody tablic w JavaScript
W tej lekcji3
Witaj ponownie w Parku Jurajskim! W poprzedniej lekcji poznaliśmy podstawy tablic w JavaScript. Teraz zagłębimy się w podstawowe metody tablic, które są niezbędne do codziennej pracy z danymi. Te metody pozwalają na dodawanie, usuwanie i manipulowanie elementami w tablicach, co jest kluczowe przy zarządzaniu inwentarzem dinozaurów, planowaniu karmienia czy organizacji personelu parku.
Modyfikacja tablic - metody zmieniające tablicę
Najpierw przyjrzyjmy się metodom, które modyfikują oryginalną tablicę. Są to tak zwane metody mutujące (ang. mutating methods).
1. push() - dodawanie elementów na końcu tablicy
Metoda push() dodaje jeden lub więcej elementów na końcu tablicy i zwraca nową długość tablicy:
1// Zarządzanie gatunkami dinozaurów w naszej zagrodzie
2const dinoEnclosure = ["T-Rex", "Velociraptor"];
3
4// Dodajemy nowy gatunek dinozaura
5dinoEnclosure.push("Dilophosaurus");
6console.log(dinoEnclosure); // ["T-Rex", "Velociraptor", "Dilophosaurus"]
7
8// Dodajemy kilka gatunków naraz
9const newLength = dinoEnclosure.push("Gallimimus", "Compsognathus");
10console.log(dinoEnclosure);
11// ["T-Rex", "Velociraptor", "Dilophosaurus", "Gallimimus", "Compsognathus"]
12console.log(`Aktualna liczba gatunków w zagrodzie: ${newLength}`); // 5Kiedy warto używać push():
- Gdy potrzebujesz dodać element(y) na końcu tablicy
- Gdy chcesz śledzić nową długość tablicy po dodaniu elementów
- Gdy kolejność elementów jest istotna, a nowy element powinien znaleźć się na końcu
2. pop() - usuwanie ostatniego elementu
Metoda pop() usuwa ostatni element z tablicy i zwraca ten element:
1// Lista dinozaurów w naszej zagrodzie
2const dinoEnclosure = ["T-Rex", "Velociraptor", "Dilophosaurus", "Compsognathus"];
3
4// Przenoszenie ostatniego dinozaura do nowej zagrody
5const removedDino = dinoEnclosure.pop();
6console.log(`Przeniesiono dinozaura: ${removedDino}`); // "Compsognathus"
7console.log("Pozostałe dinozaury:", dinoEnclosure); // ["T-Rex", "Velociraptor", "Dilophosaurus"]
8
9// Możemy kontynuować usuwanie
10const anotherRemovedDino = dinoEnclosure.pop();
11console.log(`Przeniesiono kolejnego dinozaura: ${anotherRemovedDino}`); // "Dilophosaurus"
12console.log("Aktualna zawartość zagrody:", dinoEnclosure); // ["T-Rex", "Velociraptor"]Kiedy warto używać pop():
- Gdy potrzebujesz usunąć ostatni element z tablicy
- Gdy potrzebujesz pobrać wartość usuwanego elementu
- Implementując struktury danych typu stos (LIFO - Last In, First Out)
3. unshift() - dodawanie elementów na początku
Metoda unshift() dodaje jeden lub więcej elementów na początku tablicy i zwraca nową długość tablicy:
1// Kolejka dinozaurów oczekujących na badania
2const dinoQueue = ["Velociraptor", "Triceratops"];
3
4// Priorytetowe dodanie T-Rexa na początek kolejki
5dinoQueue.unshift("T-Rex");
6console.log("Aktualna kolejka:", dinoQueue); // ["T-Rex", "Velociraptor", "Triceratops"]
7
8// Dodanie kilku dinozaurów naraz na początek
9const newQueueSize = dinoQueue.unshift("Brachiosaurus", "Stegosaurus");
10console.log("Aktualna kolejka:", dinoQueue);
11// ["Brachiosaurus", "Stegosaurus", "T-Rex", "Velociraptor", "Triceratops"]
12console.log(`Liczba dinozaurów w kolejce: ${newQueueSize}`); // 5Kiedy warto używać unshift():
- Gdy chcesz dodać element na początek tablicy
- Implementując kolejki priorytetowe, gdzie elementy z wyższym priorytetem idą na początek
- Gdy potrzebujesz śledzić nową długość tablicy
4. shift() - usuwanie pierwszego elementu
Metoda shift() usuwa pierwszy element z tablicy i zwraca ten element:
1// Kolejka dinozaurów oczekujących na badania
2const dinoQueue = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
3
4// Pobieramy pierwszego dinozaura do badań
5const nextDino = dinoQueue.shift();
6console.log(`Badamy dinozaura: ${nextDino}`); // "T-Rex"
7console.log("Pozostała kolejka:", dinoQueue); // ["Velociraptor", "Triceratops", "Stegosaurus"]
8
9// Obsługa kolejnego dinozaura
10const anotherDino = dinoQueue.shift();
11console.log(`Następny dinozaur do badań: ${anotherDino}`); // "Velociraptor"
12console.log("Aktualny stan kolejki:", dinoQueue); // ["Triceratops", "Stegosaurus"]Kiedy warto używać shift():
- Gdy potrzebujesz usunąć i pobrać pierwszy element tablicy
- Implementując kolejki (FIFO - First In, First Out)
- Przetwarzając elementy w kolejności ich dodania
5. splice() - modyfikacja elementów w dowolnym miejscu
Metoda splice() zmienia zawartość tablicy, usuwając, zamieniając lub dodając elementy. Jest niezwykle wszechstronna, ponieważ pozwala na modyfikację tablicy w dowolnym miejscu.
Podstawowa składnia: array.splice(startIndex, deleteCount, item1, item2, ...):
startIndex: indeks, od którego zacząć zmianędeleteCount: liczba elementów do usunięciaitem1, item2, ...: (opcjonalnie) elementy do dodania
5.1. Usuwanie elementów za pomocą splice()
1// Lista gatunków dinozaurów w parku
2const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"];
3
4// Usuwamy 2 elementy zaczynając od indeksu 1 (drugiego elementu)
5const removedDinos = dinosaurs.splice(1, 2);
6console.log("Usunięte dinozaury:", removedDinos); // ["Velociraptor", "Triceratops"]
7console.log("Pozostałe dinozaury:", dinosaurs); // ["T-Rex", "Stegosaurus", "Brachiosaurus"]5.2. Zastępowanie elementów za pomocą splice()
1// Lista gatunków dinozaurów
2const dinosaurs = ["T-Rex", "Dilophosaurus", "Triceratops", "Stegosaurus"];
3
4// Zastępujemy Dilophosaurus przez Velociraptor
5const replaced = dinosaurs.splice(1, 1, "Velociraptor");
6console.log("Zastąpiony dinozaur:", replaced); // ["Dilophosaurus"]
7console.log("Aktualna lista:", dinosaurs); // ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"]
8
9// Zastępujemy wiele elementów naraz
10dinosaurs.splice(2, 2, "Brachiosaurus", "Ankylosaurus", "Parasaurolophus");
11console.log("Nowy skład:", dinosaurs);
12// ["T-Rex", "Velociraptor", "Brachiosaurus", "Ankylosaurus", "Parasaurolophus"]5.3. Dodawanie elementów bez usuwania
1// Lista gatunków dinozaurów
2const dinosaurs = ["T-Rex", "Velociraptor"];
3
4// Dodajemy nowe gatunki na indeksie 1 (między T-Rex a Velociraptor)
5dinosaurs.splice(1, 0, "Dilophosaurus", "Compsognathus");
6console.log(dinosaurs); // ["T-Rex", "Dilophosaurus", "Compsognathus", "Velociraptor"]Kiedy warto używać splice():
- Gdy potrzebujesz modyfikować tablicę w określonym miejscu, a nie tylko na końcu czy początku
- Gdy potrzebujesz usunąć i/lub dodać elementy jednocześnie
- Gdy chcesz zastąpić sekcję tablicy nowymi wartościami
6. sort() - sortowanie tablicy
Metoda sort() sortuje elementy tablicy na miejscu i zwraca posortowaną tablicę:
1// Lista dinozaurów do karmienia
2const feedingList = ["Velociraptor", "T-Rex", "Dilophosaurus", "Gallimimus", "Compsognathus"];
3
4// Sortowanie alfabetyczne
5feedingList.sort();
6console.log("Lista karmienia (alfabetycznie):", feedingList);
7// ["Compsognathus", "Dilophosaurus", "Gallimimus", "T-Rex", "Velociraptor"]
8
9// Tablica z wymiarami dinozaurów (w cm)
10const dinoSizes = [1200, 300, 800, 2000, 40];
11
12// Domyślne sortowanie traktuje liczby jako stringi - to nie zadziała poprawnie!
13dinoSizes.sort();
14console.log("Niepoprawnie posortowane wymiary:", dinoSizes);
15// Prawdopodobnie: [1200, 2000, 300, 40, 800] - niepoprawnie!
16
17// Właściwe sortowanie liczb z funkcją porównującą
18dinoSizes.sort((a, b) => a - b);
19console.log("Poprawnie posortowane wymiary (rosnąco):", dinoSizes);
20// [40, 300, 800, 1200, 2000]
21
22// Sortowanie malejąco
23dinoSizes.sort((a, b) => b - a);
24console.log("Wymiary posortowane malejąco:", dinoSizes);
25// [2000, 1200, 800, 300, 40]Sortowanie obiektów
1// Dane dinozaurów do karmienia
2const dinosaurs = [
3 { name: "T-Rex", weight: 7000, priority: 1 },
4 { name: "Velociraptor", weight: 100, priority: 2 },
5 { name: "Triceratops", weight: 9000, priority: 3 },
6 { name: "Gallimimus", weight: 450, priority: 4 }
7];
8
9// Sortowanie według priorytetu karmienia
10dinosaurs.sort((a, b) => a.priority - b.priority);
11console.log("Kolejność karmienia według priorytetu:");
12dinosaurs.forEach(dino => console.log(`${dino.name} (priorytet: ${dino.priority})`));
13
14// Sortowanie według wagi (od najcięższego)
15dinosaurs.sort((a, b) => b.weight - a.weight);
16console.log("\nKolejność według wagi (od najcięższego):");
17dinosaurs.forEach(dino => console.log(`${dino.name} (${dino.weight} kg)`));
18
19// Sortowanie alfabetycznie według nazwy
20dinosaurs.sort((a, b) => a.name.localeCompare(b.name));
21console.log("\nDinozaury alfabetycznie:");
22dinosaurs.forEach(dino => console.log(`${dino.name}`));Metoda sort() przyjmuje opcjonalną funkcję porównującą, która powinna zwrócić:
- Wartość ujemną, jeśli a powinno być przed b
- Zero, jeśli a i b są równoważne pod względem sortowania
- Wartość dodatnią, jeśli a powinno być po b
Kiedy warto używać sort():
- Gdy potrzebujesz uporządkować elementy tablicy według określonego kryterium
- Gdy pracujesz z listami, które muszą być prezentowane w określonej kolejności
- Gdy implementujesz funkcjonalność sortowania w aplikacji
7. reverse() - odwrócenie kolejności tablicy
Metoda reverse() odwraca kolejność elementów w tablicy i zwraca odwróconą tablicę:
1// Lista dinozaurów od najstarszego do najmłodszego
2const dinosaursByAge = ["Brachiosaurus", "Stegosaurus", "Triceratops", "Velociraptor", "T-Rex"];
3
4// Odwrócenie kolejności, aby uzyskać listę od najmłodszego do najstarszego
5dinosaursByAge.reverse();
6console.log("Od najmłodszego do najstarszego:", dinosaursByAge);
7// ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus", "Brachiosaurus"]
8
9// Często używana w połączeniu z sort()
10const dinoHeights = [500, 900, 200, 1200, 350];
11// Sortowanie malejąco poprzez sortowanie rosnąco + odwrócenie
12dinoHeights.sort((a, b) => a - b).reverse();
13console.log("Wysokości malejąco:", dinoHeights);
14// [1200, 900, 500, 350, 200]Kiedy warto używać reverse():
- Gdy potrzebujesz odwrócić kolejność elementów w tablicy
- Gdy chcesz zmienić porządek z rosnącego na malejący (lub odwrotnie) po sortowaniu
- Gdy implementujesz funkcjonalność "odwróć kolejność" w interfejsie użytkownika
8. fill() - wypełnianie tablicy wartością
Metoda fill() wypełnia wszystkie elementy tablicy od indeksu startowego do indeksu końcowego (nie wliczając) określoną wartością:
1// Przygotowanie tablicy na pomiary temperatury dinozaurów (10 pomiarów)
2const temperatures = new Array(10);
3
4// Wypełnienie domyślną wartością (38.5 stopni Celsjusza)
5temperatures.fill(38.5);
6console.log("Domyślne temperatury:", temperatures);
7// [38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5, 38.5]
8
9// Wypełnienie tylko części tablicy
10temperatures.fill(39.2, 2, 5); // Od indeksu 2 (włącznie) do 5 (wyłączając)
11console.log("Zaktualizowane temperatury:", temperatures);
12// [38.5, 38.5, 39.2, 39.2, 39.2, 38.5, 38.5, 38.5, 38.5, 38.5]
13
14// Użycie z nową tablicą i indeksami ujemnymi (liczone od końca)
15const feedingSchedule = new Array(7).fill("Standardowe");
16feedingSchedule.fill("Zwiększona porcja", -3); // Ostatnie 3 dni
17console.log("Plan karmienia na tydzień:", feedingSchedule);
18// ["Standardowe", "Standardowe", "Standardowe", "Standardowe", "Zwiększona porcja", "Zwiększona porcja", "Zwiększona porcja"]Kiedy warto używać fill():
- Gdy tworzysz nową tablicę i potrzebujesz wypełnić ją określoną wartością początkową
- Gdy potrzebujesz zastąpić wszystkie lub niektóre wartości w istniejącej tablicy
- Gdy inicjalizujesz tablice do przechowywania danych z domyślnymi wartościami
Zastosowanie podstawowych metod tablic w praktyce
Teraz połączmy poznane metody, aby rozwiązać bardziej praktyczne scenariusze w naszym Parku Jurajskim:
Przykład 1: System zarządzania karmą dla dinozaurów
1// System zarządzania karmą dla dinozaurów
2const feedingSystem = {
3 // Stan systemu
4 foodInventory: [],
5 feedingQueue: [],
6 feedingHistory: [],
7
8 // Dodawanie nowego zapasu karmy
9 addFoodSupply: function(type, quantity, expirationDate) {
10 const supply = { type, quantity, expirationDate, addedOn: new Date() };
11 this.foodInventory.push(supply);
12
13 // Sortowanie według daty ważności (najkrótszej)
14 this.foodInventory.sort((a, b) =>
15 new Date(a.expirationDate) - new Date(b.expirationDate)
16 );
17
18 console.log(`Dodano ${quantity}kg karmy typu "${type}" do zapasów.`);
19 return supply;
20 },
21
22 // Dodawanie dinozaura do kolejki karmienia
23 scheduleDinoFeeding: function(dinoId, dinoName, foodType, quantity, priority) {
24 const feedingRequest = {
25 dinoId,
26 dinoName,
27 foodType,
28 quantity,
29 priority,
30 scheduledAt: new Date()
31 };
32
33 if (priority === "high") {
34 // Dodaj na początek kolejki
35 this.feedingQueue.unshift(feedingRequest);
36 } else {
37 // Dodaj na koniec kolejki
38 this.feedingQueue.push(feedingRequest);
39 }
40
41 console.log(`Zaplanowano karmienie dla ${dinoName} (priorytet: ${priority})`);
42 return this.feedingQueue.length;
43 },
44
45 // Pobieranie następnego dinozaura do nakarmienia
46 getNextDinoToFeed: function() {
47 if (this.feedingQueue.length === 0) {
48 console.log("Wszystkie dinozaury nakarmione. Kolejka pusta.");
49 return null;
50 }
51
52 const nextFeeding = this.feedingQueue.shift();
53 console.log(`Następny do karmienia: ${nextFeeding.dinoName}`);
54 return nextFeeding;
55 },
56
57 // Wydawanie karmy ze spichlerza
58 dispenseFoodForDino: function(dinoFeeding) {
59 const { foodType, quantity, dinoName } = dinoFeeding;
60
61 // Szukanie odpowiedniego zapasu karmy
62 let remainingQuantity = quantity;
63 const usedSupplies = [];
64
65 // Iterujemy od najstarszego zapasu (który wygasa najszybciej)
66 for (let i = 0; i < this.foodInventory.length && remainingQuantity > 0; i++) {
67 const supply = this.foodInventory[i];
68
69 if (supply.type === foodType && supply.quantity > 0) {
70 // Ile możemy pobrać z tego zapasu
71 const amountToTake = Math.min(remainingQuantity, supply.quantity);
72 supply.quantity -= amountToTake;
73 remainingQuantity -= amountToTake;
74
75 usedSupplies.push({
76 type: supply.type,
77 amount: amountToTake,
78 expirationDate: supply.expirationDate
79 });
80
81 // Jeśli zapas się skończył, usuwamy go z inwentarza
82 if (supply.quantity === 0) {
83 this.foodInventory.splice(i, 1);
84 i--; // Dostosuj indeks po usunięciu elementu
85 }
86 }
87 }
88
89 // Dodaj rekord do historii karmienia
90 const feedingRecord = {
91 ...dinoFeeding,
92 fedAt: new Date(),
93 suppliesUsed: usedSupplies,
94 fullyFed: remainingQuantity === 0
95 };
96
97 this.feedingHistory.push(feedingRecord);
98
99 if (remainingQuantity > 0) {
100 console.log(`UWAGA: Brakuje ${remainingQuantity}kg karmy typu "${foodType}" dla ${dinoName}!`);
101 return false;
102 }
103
104 console.log(`Nakarmiono ${dinoName} używając ${quantity}kg karmy typu "${foodType}".`);
105 return feedingRecord;
106 },
107
108 // Przeprowadzenie pełnego procesu karmienia
109 processFeedingCycle: function(maxFeedings = 5) {
110 console.log("=== ROZPOCZĘCIE CYKLU KARMIENIA ===");
111 let feedingsProcessed = 0;
112
113 // Przetwarzamy określoną liczbę karmień lub dopóki kolejka się nie opróżni
114 while (feedingsProcessed < maxFeedings && this.feedingQueue.length > 0) {
115 const nextDino = this.getNextDinoToFeed();
116
117 if (nextDino) {
118 const result = this.dispenseFoodForDino(nextDino);
119
120 if (!result) {
121 // Jeśli nie udało się nakarmić, przenosimy dinozaura na koniec kolejki
122 this.feedingQueue.push({
123 ...nextDino,
124 priority: "high", // Podnosimy priorytet dla nienakarmionego dinozaura
125 scheduledAt: new Date()
126 });
127 console.log(`${nextDino.dinoName} przesunięty na koniec kolejki z wysokim priorytetem.`);
128 }
129
130 feedingsProcessed++;
131 }
132 }
133
134 console.log(`=== ZAKOŃCZENIE CYKLU KARMIENIA (przetworzono: ${feedingsProcessed}) ===`);
135 console.log(`Pozostało w kolejce: ${this.feedingQueue.length} dinozaurów`);
136 return feedingsProcessed;
137 },
138
139 // Raportowanie stanu zapasów
140 reportInventoryStatus: function() {
141 console.log("=== RAPORT STANU ZAPASÓW ===");
142
143 if (this.foodInventory.length === 0) {
144 console.log("Magazyn jest pusty! Zamów nowe zapasy karmy!");
145 return { isEmpty: true, totalQuantity: 0, types: [] };
146 }
147
148 // Grupowanie zapasów według typu
149 const inventory = this.foodInventory.reduce((acc, supply) => {
150 if (!acc[supply.type]) {
151 acc[supply.type] = 0;
152 }
153 acc[supply.type] += supply.quantity;
154 return acc;
155 }, {});
156
157 // Obliczanie łącznej ilości
158 const totalQuantity = Object.values(inventory).reduce((sum, qty) => sum + qty, 0);
159
160 console.log(`Łączna ilość karmy: ${totalQuantity}kg`);
161 Object.entries(inventory).forEach(([type, qty]) => {
162 console.log(`- ${type}: ${qty}kg`);
163 });
164
165 // Sprawdzenie zapasów, które wkrótce wygasną (w ciągu 3 dni)
166 const today = new Date();
167 const threeDaysLater = new Date(today);
168 threeDaysLater.setDate(today.getDate() + 3);
169
170 const expiringSupplies = this.foodInventory.filter(supply =>
171 new Date(supply.expirationDate) <= threeDaysLater
172 );
173
174 if (expiringSupplies.length > 0) {
175 console.log("\nZapasy wygasające w ciągu 3 dni:");
176 expiringSupplies.forEach(supply => {
177 console.log(`- ${supply.quantity}kg ${supply.type} (wygasa: ${supply.expirationDate})`);
178 });
179 }
180
181 return {
182 isEmpty: false,
183 totalQuantity,
184 types: Object.keys(inventory),
185 inventory,
186 expiringSupplies
187 };
188 }
189};
190
191// Demonstracja działania systemu
192console.log("=== DEMONSTRACJA SYSTEMU ZARZĄDZANIA KARMĄ ===");
193
194// 1. Dodawanie zapasów karmy
195feedingSystem.addFoodSupply("Mięso", 500, "2023-07-15");
196feedingSystem.addFoodSupply("Rośliny", 800, "2023-07-10");
197feedingSystem.addFoodSupply("Ryby", 200, "2023-07-05");
198feedingSystem.addFoodSupply("Mięso", 300, "2023-07-20");
199
200// 2. Planowanie karmienia
201feedingSystem.scheduleDinoFeeding("TRX-01", "Rex", "Mięso", 150, "high");
202feedingSystem.scheduleDinoFeeding("VEL-02", "Blue", "Mięso", 50, "normal");
203feedingSystem.scheduleDinoFeeding("TRCP-03", "Trixie", "Rośliny", 120, "normal");
204feedingSystem.scheduleDinoFeeding("BRCH-04", "Bronty", "Rośliny", 250, "normal");
205feedingSystem.scheduleDinoFeeding("STEG-05", "Spike", "Rośliny", 100, "high");
206
207// 3. Raport stanu zapasów przed karmieniem
208feedingSystem.reportInventoryStatus();
209
210// 4. Przeprowadzanie cyklu karmienia
211feedingSystem.processFeedingCycle(3); // Przetwarzamy tylko 3 karmienia
212
213// 5. Sprawdzamy stan zapasów po karmieniu
214feedingSystem.reportInventoryStatus();
215
216// 6. Dokończenie cyklu karmienia
217feedingSystem.processFeedingCycle(5); // Przetwarzamy pozostałe karmienia
218
219// 7. Sprawdzamy stan zapasów po pełnym cyklu
220feedingSystem.reportInventoryStatus();Przykład 2: Zarządzanie zespołami pracowników parku
1// System zarządzania zespołami pracowników Parku Jurajskiego
2const staffManagementSystem = {
3 // Dane systemu
4 departments: [
5 { id: "OPS", name: "Operacje" },
6 { id: "SCI", name: "Badania naukowe" },
7 { id: "SEC", name: "Bezpieczeństwo" },
8 { id: "VET", name: "Weterynaria" },
9 { id: "MAINT", name: "Konserwacja" }
10 ],
11 staff: [],
12 teams: [],
13
14 // Dodawanie nowego pracownika
15 addStaffMember: function(name, role, skills, departmentId) {
16 // Sprawdzenie, czy dział istnieje
17 const department = this.departments.find(dept => dept.id === departmentId);
18 if (!department) {
19 console.log(`Błąd: Dział o ID "${departmentId}" nie istnieje.`);
20 return null;
21 }
22
23 // Generowanie ID pracownika
24 const id = `${departmentId}-${(this.staff.length + 1).toString().padStart(3, '0')}`;
25
26 const staffMember = {
27 id,
28 name,
29 role,
30 skills: Array.isArray(skills) ? skills : [skills],
31 departmentId,
32 departmentName: department.name,
33 hireDate: new Date().toISOString().split('T')[0]
34 };
35
36 this.staff.push(staffMember);
37 console.log(`Dodano pracownika: ${name} (${role}) do działu ${department.name}`);
38
39 return staffMember;
40 },
41
42 // Utworzenie nowego zespołu
43 createTeam: function(name, mission, leaderId) {
44 // Sprawdzenie, czy leader istnieje
45 const leader = this.staff.find(person => person.id === leaderId);
46 if (!leader) {
47 console.log(`Błąd: Pracownik o ID "${leaderId}" nie istnieje.`);
48 return null;
49 }
50
51 const teamId = `TEAM-${(this.teams.length + 1).toString().padStart(3, '0')}`;
52
53 const team = {
54 id: teamId,
55 name,
56 mission,
57 createdAt: new Date().toISOString().split('T')[0],
58 leaderId,
59 leaderName: leader.name,
60 members: [leaderId],
61 status: "active"
62 };
63
64 this.teams.push(team);
65 console.log(`Utworzono zespół: ${name} (misja: ${mission}), prowadzący: ${leader.name}`);
66
67 return team;
68 },
69
70 // Dodawanie pracownika do zespołu
71 addMemberToTeam: function(teamId, memberId) {
72 // Znajdź zespół
73 const teamIndex = this.teams.findIndex(team => team.id === teamId);
74 if (teamIndex === -1) {
75 console.log(`Błąd: Zespół o ID "${teamId}" nie istnieje.`);
76 return false;
77 }
78
79 // Znajdź pracownika
80 const member = this.staff.find(person => person.id === memberId);
81 if (!member) {
82 console.log(`Błąd: Pracownik o ID "${memberId}" nie istnieje.`);
83 return false;
84 }
85
86 // Sprawdź, czy pracownik już jest w zespole
87 if (this.teams[teamIndex].members.includes(memberId)) {
88 console.log(`${member.name} już jest członkiem zespołu ${this.teams[teamIndex].name}.`);
89 return false;
90 }
91
92 // Dodaj pracownika do zespołu
93 this.teams[teamIndex].members.push(memberId);
94 console.log(`Dodano ${member.name} do zespołu ${this.teams[teamIndex].name}.`);
95
96 return true;
97 },
98
99 // Usunięcie pracownika z zespołu
100 removeMemberFromTeam: function(teamId, memberId) {
101 // Znajdź zespół
102 const teamIndex = this.teams.findIndex(team => team.id === teamId);
103 if (teamIndex === -1) {
104 console.log(`Błąd: Zespół o ID "${teamId}" nie istnieje.`);
105 return false;
106 }
107
108 // Sprawdź, czy pracownik jest liderem
109 if (this.teams[teamIndex].leaderId === memberId) {
110 console.log(`Błąd: Nie można usunąć lidera zespołu. Najpierw zmień lidera.`);
111 return false;
112 }
113
114 // Znajdź indeks pracownika w zespole
115 const memberIndex = this.teams[teamIndex].members.indexOf(memberId);
116 if (memberIndex === -1) {
117 console.log(`Pracownik nie jest członkiem zespołu ${this.teams[teamIndex].name}.`);
118 return false;
119 }
120
121 // Znajdź pracownika dla celów informacyjnych
122 const member = this.staff.find(person => person.id === memberId);
123
124 // Usuń pracownika z zespołu
125 this.teams[teamIndex].members.splice(memberIndex, 1);
126 console.log(`Usunięto ${member ? member.name : memberId} z zespołu ${this.teams[teamIndex].name}.`);
127
128 return true;
129 },
130
131 // Zmiana lidera zespołu
132 changeTeamLeader: function(teamId, newLeaderId) {
133 // Znajdź zespół
134 const teamIndex = this.teams.findIndex(team => team.id === teamId);
135 if (teamIndex === -1) {
136 console.log(`Błąd: Zespół o ID "${teamId}" nie istnieje.`);
137 return false;
138 }
139
140 // Sprawdź, czy nowy lider istnieje
141 const newLeader = this.staff.find(person => person.id === newLeaderId);
142 if (!newLeader) {
143 console.log(`Błąd: Pracownik o ID "${newLeaderId}" nie istnieje.`);
144 return false;
145 }
146
147 // Sprawdź, czy nowy lider jest członkiem zespołu
148 if (!this.teams[teamIndex].members.includes(newLeaderId)) {
149 // Dodaj nowego lidera do zespołu, jeśli jeszcze nie jest członkiem
150 this.teams[teamIndex].members.push(newLeaderId);
151 console.log(`${newLeader.name} został dodany do zespołu jako nowy lider.`);
152 }
153
154 // Zapisz informacje o starym liderze dla komunikatu
155 const oldLeaderId = this.teams[teamIndex].leaderId;
156 const oldLeader = this.staff.find(person => person.id === oldLeaderId);
157
158 // Zaktualizuj lidera
159 this.teams[teamIndex].leaderId = newLeaderId;
160 this.teams[teamIndex].leaderName = newLeader.name;
161
162 console.log(`Lider zespołu ${this.teams[teamIndex].name} zmieniony z ${oldLeader.name} na ${newLeader.name}.`);
163 return true;
164 },
165
166 // Rozwiązanie zespołu
167 deactivateTeam: function(teamId, reason) {
168 // Znajdź zespół
169 const teamIndex = this.teams.findIndex(team => team.id === teamId);
170 if (teamIndex === -1) {
171 console.log(`Błąd: Zespół o ID "${teamId}" nie istnieje.`);
172 return false;
173 }
174
175 // Zapisanie stanu przed modyfikacją
176 const teamName = this.teams[teamIndex].name;
177
178 // Aktualizacja statusu zespołu
179 this.teams[teamIndex].status = "inactive";
180 this.teams[teamIndex].deactivatedAt = new Date().toISOString().split('T')[0];
181 this.teams[teamIndex].deactivationReason = reason || "Nieokreślony";
182
183 console.log(`Zespół ${teamName} został dezaktywowany. Powód: ${this.teams[teamIndex].deactivationReason}`);
184 return true;
185 },
186
187 // Generowanie raportu o zespołach
188 generateTeamsReport: function(includeInactive = false) {
189 console.log("=== RAPORT O ZESPOŁACH PARKU JURAJSKIEGO ===");
190
191 // Filtruj zespoły według statusu, jeśli nie uwzględniamy nieaktywnych
192 const teamsToReport = includeInactive
193 ? this.teams
194 : this.teams.filter(team => team.status === "active");
195
196 if (teamsToReport.length === 0) {
197 console.log("Brak zespołów do wyświetlenia.");
198 return { teams: [] };
199 }
200
201 // Przygotowanie danych do raportu
202 const teamsData = teamsToReport.map(team => {
203 // Pobierz pełne informacje o członkach
204 const memberDetails = team.members.map(memberId => {
205 const member = this.staff.find(person => person.id === memberId);
206 return member ? {
207 id: member.id,
208 name: member.name,
209 role: member.role,
210 isLeader: memberId === team.leaderId
211 } : { id: memberId, name: "Nieznany", role: "Nieznany", isLeader: false };
212 });
213
214 return {
215 id: team.id,
216 name: team.name,
217 mission: team.mission,
218 status: team.status,
219 memberCount: team.members.length,
220 leader: this.staff.find(person => person.id === team.leaderId),
221 members: memberDetails,
222 createdAt: team.createdAt,
223 deactivatedAt: team.deactivatedAt,
224 deactivationReason: team.deactivationReason
225 };
226 });
227
228 // Sortuj zespoły - aktywne pierwsze, potem według daty utworzenia
229 teamsData.sort((a, b) => {
230 if (a.status !== b.status) {
231 return a.status === "active" ? -1 : 1;
232 }
233 return new Date(b.createdAt) - new Date(a.createdAt);
234 });
235
236 // Wyświetl podsumowanie
237 console.log(`Liczba zespołów: ${teamsData.length}`);
238 console.log(`Aktywne zespoły: ${teamsData.filter(t => t.status === "active").length}`);
239 if (includeInactive) {
240 console.log(`Nieaktywne zespoły: ${teamsData.filter(t => t.status === "inactive").length}`);
241 }
242
243 // Wyświetl szczegóły dla każdego zespołu
244 teamsData.forEach(team => {
245 console.log(`\n${team.id}: ${team.name} (Status: ${team.status})`);
246 console.log(`Misja: ${team.mission}`);
247 console.log(`Lider: ${team.leader ? team.leader.name : 'Brak'} (${team.leader ? team.leader.role : ''})`);
248 console.log(`Liczba członków: ${team.memberCount}`);
249 console.log("Członkowie:");
250 team.members.forEach(member => {
251 console.log(` - ${member.name} (${member.role})${member.isLeader ? ' [LIDER]' : ''}`);
252 });
253
254 if (team.status === "inactive") {
255 console.log(`Dezaktywowano: ${team.deactivatedAt}`);
256 console.log(`Powód: ${team.deactivationReason}`);
257 }
258 });
259
260 return { teams: teamsData };
261 },
262
263 // Reorganizacja zespołów
264 reorganizeTeams: function(fromTeamId, toTeamId, memberIds, dissolveSourceTeam = false) {
265 // Sprawdź, czy zespoły istnieją
266 const fromTeamIndex = this.teams.findIndex(team => team.id === fromTeamId);
267 const toTeamIndex = this.teams.findIndex(team => team.id === toTeamId);
268
269 if (fromTeamIndex === -1 || toTeamIndex === -1) {
270 console.log(`Błąd: Jeden lub oba zespoły nie istnieją.`);
271 return false;
272 }
273
274 // Sprawdź, czy zespoły są aktywne
275 if (this.teams[fromTeamIndex].status !== "active" || this.teams[toTeamIndex].status !== "active") {
276 console.log(`Błąd: Zespoły muszą być aktywne, aby je reorganizować.`);
277 return false;
278 }
279
280 // Jeśli nie podano konkretnych członków, przenieś wszystkich (oprócz lidera)
281 const membersToMove = memberIds ||
282 this.teams[fromTeamIndex].members.filter(id => id !== this.teams[fromTeamIndex].leaderId);
283
284 // Przenieś członków
285 for (const memberId of membersToMove) {
286 // Sprawdź, czy pracownik jest częścią źródłowego zespołu
287 if (!this.teams[fromTeamIndex].members.includes(memberId)) {
288 console.log(`Błąd: Pracownik o ID ${memberId} nie jest członkiem zespołu źródłowego.`);
289 continue;
290 }
291
292 // Sprawdź, czy pracownik nie jest liderem (jeśli nie chcemy przenosić wszystkich)
293 if (memberIds && memberId === this.teams[fromTeamIndex].leaderId) {
294 console.log(`Nie można przenieść lidera zespołu. Najpierw zmień lidera.`);
295 continue;
296 }
297
298 // Sprawdź, czy pracownik już jest częścią docelowego zespołu
299 if (this.teams[toTeamIndex].members.includes(memberId)) {
300 console.log(`Pracownik o ID ${memberId} już jest członkiem zespołu docelowego.`);
301 continue;
302 }
303
304 // Usuń z pierwotnego zespołu
305 const fromIndex = this.teams[fromTeamIndex].members.indexOf(memberId);
306 this.teams[fromTeamIndex].members.splice(fromIndex, 1);
307
308 // Dodaj do nowego zespołu
309 this.teams[toTeamIndex].members.push(memberId);
310
311 // Znajdź nazwę pracownika dla logów
312 const member = this.staff.find(person => person.id === memberId);
313 console.log(`Przeniesiono ${member ? member.name : memberId} z zespołu ${this.teams[fromTeamIndex].name} do ${this.teams[toTeamIndex].name}`);
314 }
315
316 // Jeśli wybrano rozwiązanie źródłowego zespołu i nie ma już członków
317 if (dissolveSourceTeam || this.teams[fromTeamIndex].members.length === 0) {
318 this.deactivateTeam(fromTeamId, "Reorganizacja - zespół przeniesiony");
319 }
320
321 return true;
322 }
323};
324
325// Demonstracja działania systemu zarządzania zespołami
326console.log("=== DEMONSTRACJA SYSTEMU ZARZĄDZANIA ZESPOŁAMI ===");
327
328// 1. Dodawanie pracowników
329const owen = staffManagementSystem.addStaffMember("Owen Grady", "Trener dinozaurów", ["Zachowania zwierząt", "Tresura", "Pierwsza pomoc"], "OPS");
330const claire = staffManagementSystem.addStaffMember("Claire Dearing", "Dyrektor operacyjny", ["Zarządzanie", "Marketing", "Administracja"], "OPS");
331const dr_wu = staffManagementSystem.addStaffMember("Dr. Henry Wu", "Główny genetyk", ["Genetyka", "Bioinżynieria", "Klonowanie"], "SCI");
332const barry = staffManagementSystem.addStaffMember("Barry", "Asystent trenera", ["Tresura", "Opieka nad zwierzętami"], "OPS");
333const lowery = staffManagementSystem.addStaffMember("Lowery Cruthers", "Technik systemów", ["IT", "Monitoring", "Komunikacja"], "SEC");
334const vivian = staffManagementSystem.addStaffMember("Vivian Krill", "Koordynator bezpieczeństwa", ["Bezpieczeństwo", "Komunikacja", "Zarządzanie kryzysowe"], "SEC");
335const muldoon = staffManagementSystem.addStaffMember("Robert Muldoon", "Specjalista ds. bezpieczeństwa", ["Broń", "Bezpieczeństwo", "Tropienie"], "SEC");
336const malcolm = staffManagementSystem.addStaffMember("Dr. Ian Malcolm", "Matematyk", ["Teoria chaosu", "Analiza ryzyka", "Modelowanie"], "SCI");
337const sattler = staffManagementSystem.addStaffMember("Dr. Ellie Sattler", "Paleobotanik", ["Botanika", "Paleontologia", "Ekologia"], "SCI");
338const harding = staffManagementSystem.addStaffMember("Dr. Gerry Harding", "Weterynarz", ["Weterynaria", "Zoologia", "Medycyna"], "VET");
339
340// 2. Tworzenie zespołów
341const raptorTeam = staffManagementSystem.createTeam("Zespół Velociraptor", "Tresura i opieka nad Velociraptorami", owen.id);
342staffManagementSystem.addMemberToTeam(raptorTeam.id, barry.id);
343
344const securityTeam = staffManagementSystem.createTeam("Zespół Bezpieczeństwa", "Zapewnienie bezpieczeństwa w parku", muldoon.id);
345staffManagementSystem.addMemberToTeam(securityTeam.id, vivian.id);
346staffManagementSystem.addMemberToTeam(securityTeam.id, lowery.id);
347
348const scienceTeam = staffManagementSystem.createTeam("Zespół Naukowy", "Badania naukowe i rozwój", dr_wu.id);
349staffManagementSystem.addMemberToTeam(scienceTeam.id, malcolm.id);
350staffManagementSystem.addMemberToTeam(scienceTeam.id, sattler.id);
351
352// 3. Raport o zespołach
353staffManagementSystem.generateTeamsReport();
354
355// 4. Reorganizacja zespołów
356console.log("\n=== REORGANIZACJA ZESPOŁÓW ===");
357
358// Tworzenie nowego zespołu zarządzania kryzysowego
359const crisisTeam = staffManagementSystem.createTeam("Zespół Zarządzania Kryzysowego", "Reagowanie na sytuacje kryzysowe", claire.id);
360
361// Przenoszenie członków z innych zespołów
362staffManagementSystem.reorganizeTeams(securityTeam.id, crisisTeam.id, [vivian.id]);
363staffManagementSystem.addMemberToTeam(crisisTeam.id, malcolm.id); // Dodajemy Malcolma jako doradcę ds. ryzyka
364staffManagementSystem.addMemberToTeam(crisisTeam.id, harding.id); // Dodajemy weterynarza
365
366// Zmiana lidera zespołu naukowego
367staffManagementSystem.changeTeamLeader(scienceTeam.id, sattler.id);
368
369// Dezaktywacja jednego zespołu
370staffManagementSystem.deactivateTeam(raptorTeam.id, "Projekt zawieszony - incydent z raptorami");
371
372// 5. Finalny raport o zespołach (z uwzględnieniem nieaktywnych)
373staffManagementSystem.generateTeamsReport(true);Podsumowanie
W tej lekcji poznaliśmy podstawowe metody modyfikacji tablic w JavaScript:
- push() - dodaje elementy na końcu tablicy
- pop() - usuwa i zwraca ostatni element tablicy
- unshift() - dodaje elementy na początku tablicy
- shift() - usuwa i zwraca pierwszy element tablicy
- splice() - dodaje, usuwa lub zastępuje elementy w dowolnym miejscu tablicy
- sort() - sortuje elementy tablicy
- reverse() - odwraca kolejność elementów w tablicy
- fill() - wypełnia elementy tablicy określoną wartością
Umiejętność efektywnego wykorzystania tych metod jest kluczowa przy pracy z danymi w JavaScript. Pozwalają one na zarządzanie kolekcjami, implementowanie struktur danych (takich jak stosy i kolejki) oraz efektywną manipulację danymi.
Warto pamiętać, że powyższe metody modyfikują oryginalną tablicę (z wyjątkiem przypadków, gdy tworzymy kopię przed ich zastosowaniem). W jednej z kolejnych lekcji poznamy metody tablic, które nie modyfikują oryginału, ale zwracają nową tablicę lub wartość.
Kod do tej lekcji: index.js
1// Metody tablic - Park Jurajski
2console.log("Laboratorium Metod Tablic");
3console.log("Zaawansowane operacje na kolekcjach\n");
4
5// ===========================================
6// 1. forEach() - ITERACJA
7// ===========================================
8console.log("=== 1. forEach() - Iteracja ===");
9
10const dinosaurs = ["T-Rex", "Velociraptor", "Triceratops", "Stegosaurus"];
11
12console.log("\nLista dinozaurów:");
13dinosaurs.forEach((dino, index) => {
14 console.log(` ${index + 1}. ${dino}`);
15});
16
17// forEach z pełnymi parametrami
18console.log("\nPełna wersja forEach:");
19dinosaurs.forEach((element, index, array) => {
20 console.log(` [${index}] ${element} z tablicy długości ${array.length}`);
21});
22
23// ===========================================
24// 2. map() - TRANSFORMACJA
25// ===========================================
26console.log("\n=== 2. map() - Transformacja ===");
27
28const dinoData = [
29 { name: "T-Rex", weight: 8000 },
30 { name: "Velociraptor", weight: 80 },
31 { name: "Triceratops", weight: 9000 }
32];
33
34// Wyciągnięcie samych nazw
35const names = dinoData.map(dino => dino.name);
36console.log("\nSame nazwy:", names);
37
38// Transformacja do nowego formatu
39const formatted = dinoData.map(dino => ({
40 species: dino.name,
41 weightInTons: dino.weight / 1000,
42 category: dino.weight > 1000 ? "Duży" : "Mały"
43}));
44
45console.log("\nPrzetransformowane:");
46formatted.forEach(d => {
47 console.log(` ${d.species}: ${d.weightInTons}t - ${d.category}`);
48});
49
50// ===========================================
51// 3. filter() - FILTROWANIE
52// ===========================================
53console.log("\n=== 3. filter() - Filtrowanie ===");
54
55const allDinos = [
56 { name: "T-Rex", weight: 8000, carnivore: true },
57 { name: "Velociraptor", weight: 80, carnivore: true },
58 { name: "Triceratops", weight: 9000, carnivore: false },
59 { name: "Stegosaurus", weight: 5000, carnivore: false },
60 { name: "Brachiosaurus", weight: 50000, carnivore: false }
61];
62
63// Tylko mięsożercy
64const carnivores = allDinos.filter(dino => dino.carnivore);
65console.log("\nMięsożercy:", carnivores.map(d => d.name));
66
67// Ciężkie dinozaury (> 5000kg)
68const heavy = allDinos.filter(dino => dino.weight > 5000);
69console.log("Ciężkie (>5t):", heavy.map(d => d.name));
70
71// Łączenie warunków
72const heavyCarnivores = allDinos.filter(d => d.carnivore && d.weight > 100);
73console.log("Ciężkie mięsożercy:", heavyCarnivores.map(d => d.name));
74
75// ===========================================
76// 4. find() i findIndex()
77// ===========================================
78console.log("\n=== 4. find() i findIndex() ===");
79
80const park = [
81 { id: 1, name: "T-Rex", sector: "A" },
82 { id: 2, name: "Velociraptor", sector: "B" },
83 { id: 3, name: "Triceratops", sector: "C" }
84];
85
86// find() - pierwszy element spełniający warunek
87const foundDino = park.find(dino => dino.sector === "B");
88console.log("\nfind(sector === 'B'):", foundDino);
89
90// findIndex() - indeks pierwszego elementu
91const foundIndex = park.findIndex(dino => dino.name === "Triceratops");
92console.log("findIndex(name === 'Triceratops'):", foundIndex);
93
94// Nieznaleziony element
95const notFound = park.find(dino => dino.name === "Pteranodon");
96console.log("find(Pteranodon):", notFound); // undefined
97
98// ===========================================
99// 5. reduce() - AGREGACJA
100// ===========================================
101console.log("\n=== 5. reduce() - Agregacja ===");
102
103const weights = [
104 { name: "T-Rex", weight: 8000 },
105 { name: "Velociraptor", weight: 80 },
106 { name: "Triceratops", weight: 9000 },
107 { name: "Stegosaurus", weight: 5000 }
108];
109
110// Suma wag
111const totalWeight = weights.reduce((sum, dino) => sum + dino.weight, 0);
112console.log(`\nŁączna waga: ${totalWeight}kg`);
113
114// Średnia waga
115const avgWeight = totalWeight / weights.length;
116console.log(`Średnia waga: ${avgWeight.toFixed(2)}kg`);
117
118// Grupowanie po wadze
119const grouped = weights.reduce((acc, dino) => {
120 const category = dino.weight > 1000 ? "heavy" : "light";
121 if (!acc[category]) acc[category] = [];
122 acc[category].push(dino.name);
123 return acc;
124}, {});
125
126console.log("\nPogrupowane:");
127console.log(" Ciężkie:", grouped.heavy);
128console.log(" Lekkie:", grouped.light);
129
130// Znajdowanie max
131const heaviest = weights.reduce((max, dino) =>
132 dino.weight > max.weight ? dino : max
133);
134console.log(`\nNajcięższy: ${heaviest.name} (${heaviest.weight}kg)`);
135
136// ===========================================
137// 6. some() i every()
138// ===========================================
139console.log("\n=== 6. some() i every() ===");
140
141const herd = [
142 { name: "Trike", health: 95 },
143 { name: "Stego", health: 88 },
144 { name: "Brachio", health: 72 }
145];
146
147// some() - czy przynajmniej jeden
148const hasSick = herd.some(dino => dino.health < 80);
149console.log("\nCzy są chore (<80%):", hasSick);
150
151const hasHealthy = herd.some(dino => dino.health > 90);
152console.log("Czy są bardzo zdrowe (>90%):", hasHealthy);
153
154// every() - czy wszystkie
155const allHealthy = herd.every(dino => dino.health >= 80);
156console.log("Czy wszystkie zdrowe (≥80%):", allHealthy);
157
158const allCritical = herd.every(dino => dino.health < 50);
159console.log("Czy wszystkie krytyczne (<50%):", allCritical);
160
161// ===========================================
162// 7. sort() - SORTOWANIE
163// ===========================================
164console.log("\n=== 7. sort() - Sortowanie ===");
165
166const unsorted = ["Velociraptor", "T-Rex", "Brachiosaurus", "Stegosaurus"];
167
168// Alfabetycznie
169const alphabetical = [...unsorted].sort();
170console.log("\nAlfabetycznie:", alphabetical);
171
172// Odwrotnie alfabetycznie
173const reverseAlpha = [...unsorted].sort((a, b) => b.localeCompare(a));
174console.log("Odwrotnie:", reverseAlpha);
175
176// Sortowanie obiektów
177const dinoStats = [
178 { name: "T-Rex", health: 85 },
179 { name: "Velociraptor", health: 100 },
180 { name: "Triceratops", health: 70 }
181];
182
183const byHealth = [...dinoStats].sort((a, b) => b.health - a.health);
184console.log("\nPo zdrowiu (malejąco):");
185byHealth.forEach(d => console.log(` ${d.name}: ${d.health}%`));
186
187// ===========================================
188// 8. ŁAŃCUCHOWANIE METOD
189// ===========================================
190console.log("\n=== 8. Łańcuchowanie metod ===");
191
192const inventory = [
193 { name: "Rexy", species: "T-Rex", sector: "A", health: 95, carnivore: true },
194 { name: "Blue", species: "Velociraptor", sector: "B", health: 100, carnivore: true },
195 { name: "Charlie", species: "Velociraptor", sector: "B", health: 85, carnivore: true },
196 { name: "Trike", species: "Triceratops", sector: "C", health: 70, carnivore: false },
197 { name: "Stego", species: "Stegosaurus", sector: "C", health: 92, carnivore: false }
198];
199
200// Znajdź zdrowych mięsożerców i posortuj po nazwie
201const healthyCarnivores = inventory
202 .filter(d => d.carnivore)
203 .filter(d => d.health >= 90)
204 .map(d => d.name)
205 .sort();
206
207console.log("\nZdrowi mięsożercy (≥90%):", healthyCarnivores);
208
209// Suma zdrowia roślinożerców
210const herbivoreHealth = inventory
211 .filter(d => !d.carnivore)
212 .reduce((sum, d) => sum + d.health, 0);
213
214console.log(`Suma zdrowia roślinożerców: ${herbivoreHealth}%`);
215
216// ===========================================
217// 9. flat() i flatMap()
218// ===========================================
219console.log("\n=== 9. flat() i flatMap() ===");
220
221const sectors = [
222 ["T-Rex", "Spinosaurus"],
223 ["Velociraptor", "Dilophosaurus"],
224 ["Triceratops", "Stegosaurus"]
225];
226
227// flat() - spłaszczenie zagnieżdżonej tablicy
228const flatDinos = sectors.flat();
229console.log("\nflat():", flatDinos);
230
231// flatMap() - map + flat w jednym
232const withEmoji = sectors.flatMap(sector =>
233 sector.map(dino => `${dino}`)
234);
235console.log("flatMap():", withEmoji);
236
237// ===========================================
238// 10. PRZYKŁAD KOMPLEKSOWY
239// ===========================================
240console.log("\n=== 10. System analizy - przykład kompleksowy ===");
241
242class DinosaurAnalytics {
243 constructor(dinosaurs) {
244 this.dinosaurs = dinosaurs;
245 }
246
247 // Statystyki ogólne
248 getOverallStats() {
249 const total = this.dinosaurs.length;
250 const avgHealth = this.dinosaurs.reduce((sum, d) => sum + d.health, 0) / total;
251 const carnivoreCount = this.dinosaurs.filter(d => d.carnivore).length;
252
253 return {
254 total,
255 avgHealth: avgHealth.toFixed(1),
256 carnivores: carnivoreCount,
257 herbivores: total - carnivoreCount
258 };
259 }
260
261 // Top N po zdrowiu
262 getHealthiest(n = 3) {
263 return this.dinosaurs
264 .sort((a, b) => b.health - a.health)
265 .slice(0, n)
266 .map(d => ({ name: d.name, health: d.health }));
267 }
268
269 // Grupowanie po sektorze
270 groupBySector() {
271 return this.dinosaurs.reduce((acc, dino) => {
272 if (!acc[dino.sector]) acc[dino.sector] = [];
273 acc[dino.sector].push(dino.name);
274 return acc;
275 }, {});
276 }
277
278 // Alerty dla chorych
279 getHealthAlerts() {
280 return this.dinosaurs
281 .filter(d => d.health < 80)
282 .map(d => ({
283 name: d.name,
284 sector: d.sector,
285 health: d.health,
286 priority: d.health < 50 ? "KRYTYCZNY" : "UWAGA"
287 }))
288 .sort((a, b) => a.health - b.health);
289 }
290
291 // Raport sektora
292 getSectorReport(sector) {
293 const dinosInSector = this.dinosaurs.filter(d => d.sector === sector);
294
295 if (dinosInSector.length === 0) {
296 return { error: `Brak dinozaurów w sektorze ${sector}` };
297 }
298
299 const avgHealth = dinosInSector.reduce((sum, d) => sum + d.health, 0) / dinosInSector.length;
300 const carnivores = dinosInSector.filter(d => d.carnivore);
301 const herbivores = dinosInSector.filter(d => !d.carnivore);
302
303 return {
304 sector,
305 total: dinosInSector.length,
306 avgHealth: avgHealth.toFixed(1),
307 carnivores: carnivores.map(d => d.name),
308 herbivores: herbivores.map(d => d.name),
309 list: dinosInSector.map(d => `${d.name} (${d.health}%)`)
310 };
311 }
312
313 // Wyświetl wszystkie analizy
314 displayFullReport() {
315 console.log("\nPEŁNY RAPORT ANALITYCZNY");
316 console.log("=".repeat(70));
317
318 // Statystyki ogólne
319 const stats = this.getOverallStats();
320 console.log("\nStatystyki ogólne:");
321 console.log(` Łącznie dinozaurów: ${stats.total}`);
322 console.log(` Średnie zdrowie: ${stats.avgHealth}%`);
323 console.log(` Mięsożercy: ${stats.carnivores}`);
324 console.log(` Roślinożercy: ${stats.herbivores}`);
325
326 // Najzdrowsze
327 const healthiest = this.getHealthiest(3);
328 console.log("\nTOP 3 - Najzdrowsze:");
329 healthiest.forEach((d, i) => {
330 console.log(` ${i + 1}. ${d.name} - ${d.health}%`);
331 });
332
333 // Podział na sektory
334 const sectors = this.groupBySector();
335 console.log("\nPodział na sektory:");
336 Object.entries(sectors).sort().forEach(([sector, dinos]) => {
337 console.log(` Sektor ${sector}: ${dinos.join(", ")}`);
338 });
339
340 // Alerty zdrowotne
341 const alerts = this.getHealthAlerts();
342 if (alerts.length > 0) {
343 console.log("\nALERTY ZDROWOTNE:");
344 alerts.forEach(alert => {
345 console.log(` [${alert.priority}] ${alert.name} - Sektor ${alert.sector} - ${alert.health}%`);
346 });
347 } else {
348 console.log("\nBrak alertów zdrowotnych");
349 }
350
351 // Raporty sektorów
352 const uniqueSectors = [...new Set(this.dinosaurs.map(d => d.sector))].sort();
353 console.log("\nSZCZEGÓŁY SEKTORÓW:");
354 uniqueSectors.forEach(sector => {
355 const report = this.getSectorReport(sector);
356 console.log(`\n Sektor ${report.sector}:`);
357 console.log(` Dinozaury: ${report.total}`);
358 console.log(` Średnie zdrowie: ${report.avgHealth}%`);
359 if (report.carnivores.length > 0) {
360 console.log(` Mięsożercy: ${report.carnivores.join(", ")}`);
361 }
362 if (report.herbivores.length > 0) {
363 console.log(` Roślinożercy: ${report.herbivores.join(", ")}`);
364 }
365 });
366 }
367}
368
369// Dane testowe
370const testData = [
371 { name: "Rexy", species: "T-Rex", sector: "A", health: 95, carnivore: true },
372 { name: "Blue", species: "Velociraptor", sector: "B", health: 100, carnivore: true },
373 { name: "Charlie", species: "Velociraptor", sector: "B", health: 85, carnivore: true },
374 { name: "Delta", species: "Velociraptor", sector: "B", health: 45, carnivore: true },
375 { name: "Trike", species: "Triceratops", sector: "C", health: 70, carnivore: false },
376 { name: "Stego", species: "Stegosaurus", sector: "C", health: 92, carnivore: false },
377 { name: "Brachio", species: "Brachiosaurus", sector: "D", health: 88, carnivore: false }
378];
379
380// Uruchom analizę
381const analytics = new DinosaurAnalytics(testData);
382analytics.displayFullReport();
383
384console.log("\nGratulacje! Opanowałeś metody tablic!");Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Co robi metoda Array.prototype.pop()?
2. Co zwróci typeof undefined?
3. Który sposób jest najprostszy do sprawdzenia wartości zmiennej podczas debugowania?
4. Dlaczego warto używać const zamiast let, gdy wartość zmiennej nie będzie zmieniana?
Zadania praktyczne w grze
- Edytor kodu
Utwórz tablicę species z gatunkami 'T-Rex', 'Velociraptor' i 'Triceratops'. Metodą push() dodaj na koniec 'Stegosaurus', a metodą shift() usuń pierwszy element i zapisz go w stałej removed. Wyświetl w konsoli tablicę species i jej długość (length).
- Klikanie w kolejności
Ułóż elementy template literal z interpolacją:
- Edytor kodu
Zapisz jako BigInt: const dinoEraStart = 245000000n (początek ery dinozaurów w latach temu) i const dinoEraEnd = 66000000n (jej koniec). Oblicz dinoEraDuration jako różnicę dinoEraStart - dinoEraEnd, a dinoEraDays jako dinoEraDuration pomnożone przez 365n. Wyświetl oba wyniki w konsoli.
- Układanie w poziomie
Ułóż elementy sprawdzania typu zmiennej:
- Edytor kodu
Utwórz stałą species z nazwą gatunku dinozaura zapisaną jako tekst, np. 'Tyrannosaurus Rex', i zmienną age (let) z wiekiem 25. Po urodzinach zmień wartość age na 26 i wyświetl w konsoli species i age.
- Układanie w pionie
Uporządkuj miejsca, w których JavaScript szuka zmiennej (scope chain):
- Układanie w poziomie
Ułóż elementy deklaracji funkcji strzałkowej (arrow function):
- Edytor kodu
Napisz funkcję ageInMillions(years), która zwraca wiek skamieniałości w milionach lat, zaokrąglony do liczby całkowitej przez Math.round(). Wywołaj ją dla skamieniałości sprzed 66000000 lat i wyświetl wynik w konsoli.
- Klikanie w kolejności
Uporządkuj proces alokacji pamięci dla zmiennych:
- Układanie w pionie
Uporządkuj kroki sprawdzania typu zmiennej w kodzie produkcyjnym:
- Układanie w pionie
Uporządkuj wprowadzenie nowych typów danych w JavaScript chronologicznie:
- Klikanie w kolejności
Ułóż elementy deklaracji tablicy w JavaScript
- Układanie w pionie
Uporządkuj etapy zarządzania pamięcią dla zmiennych w JavaScript:
- Układanie w poziomie
Ułóż elementy dodawania elementu do tablicy: