Kurs JavaScript i TypeScript · Moduł 2: Funkcje, tablice i obiekty
Zasięg zmiennych (globalny, funkcyjny, blokowy)
W tej lekcji8
Witaj ponownie w Parku Jurajskim! Dzisiaj zajmiemy się jednym z fundamentalnych konceptów JavaScript - zasięgiem zmiennych. Zrozumienie zasięgu zmiennych jest kluczowe dla pisania wydajnego, bezpiecznego i przewidywalnego kodu, szczególnie w złożonych systemach, takich jak nasz park pełen dinozaurów.
Czym jest zasięg zmiennych?
Zasięg zmiennych (scope) określa, gdzie w kodzie dana zmienna jest dostępna - innymi słowy, z którego miejsca w kodzie możemy się do niej odwołać. Podobnie jak w Parku Jurajskim mamy strefy z różnymi poziomami dostępu (strefa dla zwiedzających, laboratorium tylko dla naukowców, zagrody wymagające specjalnych uprawnień), tak w JavaScript mamy różne zasięgi dostępu do zmiennych.
W JavaScript wyróżniamy trzy główne typy zasięgów:
- Zasięg globalny (Global scope)
- Zasięg funkcyjny (Function scope)
- Zasięg blokowy (Block scope)
Zasięg globalny
Zmienne zdefiniowane poza jakąkolwiek funkcją lub blokiem kodu mają zasięg globalny. Oznacza to, że są dostępne w całym programie, w każdej funkcji i bloku kodu.
1// Zmienne globalne - dostępne wszędzie, jak publiczne informacje o parku
2const parkName = "Jurassic Park";
3let visitorCount = 0;
4var isOpenToPublic = true;
5
6function checkParkStatus() {
7 console.log(`Nazwa parku: ${parkName}`);
8 console.log(`Liczba odwiedzających: ${visitorCount}`);
9 console.log(`Otwarty dla zwiedzających: ${isOpenToPublic}`);
10}
11
12function updateVisitorCount(newCount) {
13 // Możemy modyfikować zmienną globalną z dowolnej funkcji
14 visitorCount = newCount;
15 console.log(`Zaktualizowano liczbę odwiedzających: ${visitorCount}`);
16}
17
18// Wywołanie funkcji korzystających z globalnych zmiennych
19checkParkStatus();
20updateVisitorCount(250);
21checkParkStatus();Należy być ostrożnym ze zmiennymi globalnymi, ponieważ:
- Mogą być przypadkowo zmodyfikowane z dowolnego miejsca w kodzie
- Mogą prowadzić do konfliktów nazw
- Utrudniają śledzenie stanu aplikacji
- Zwiększają powiązania między różnymi częściami kodu
Zmienne globalne w naszym parku to jak dokumenty dostępne dla wszystkich pracowników - czasami są niezbędne, ale zbyt wiele takich dokumentów może prowadzić do bałaganu i nieporozumień.
Zasięg funkcyjny
Zmienne zdefiniowane wewnątrz funkcji są dostępne tylko wewnątrz tej funkcji. Są to zmienne lokalne dla danej funkcji.
1function monitorDinosaur(dinoId) {
2 // Te zmienne mają zasięg funkcyjny - są dostępne tylko wewnątrz tej funkcji
3 const startTime = Date.now();
4 let status = "Monitorowanie...";
5 var sensorData = [];
6
7 // Możemy używać zmiennych wewnątrz funkcji
8 status = "Zbieranie danych...";
9 sensorData.push({ time: startTime, temperature: 37.5 });
10
11 console.log(`Status: ${status}`);
12 console.log(`Dane z czujników: ${JSON.stringify(sensorData)}`);
13
14 // Zwracamy wynik
15 return {
16 id: dinoId,
17 monitoringStarted: startTime,
18 lastStatus: status
19 };
20}
21
22// Wywołanie funkcji
23const monitoringResults = monitorDinosaur("T-Rex-01");
24
25// Poniższy kod spowodowałby błąd, ponieważ próbujemy uzyskać dostęp
26// do zmiennych o zasięgu funkcyjnym z zewnątrz funkcji
27// console.log(startTime); // ReferenceError
28// console.log(status); // ReferenceError
29// console.log(sensorData); // ReferenceError
30
31// Ale mamy dostęp do wartości zwracanej przez funkcję
32console.log(monitoringResults);Zasięg funkcyjny działa jak strefy zastrzeżone w parku - tylko upoważniony personel (kod wewnątrz funkcji) ma dostęp do informacji i zasobów w tej strefie.
Różnica między var, let i const w kontekście zasięgu funkcyjnego
Wszystkie trzy słowa kluczowe (var, let, const) tworzą zmienne o zasięgu funkcyjnym, ale jest między nimi istotna różnica:
varma zasięg funkcyjny, ale nie blokowyleticonstmają zarówno zasięg funkcyjny jak i blokowy
Zobaczmy to na przykładzie:
1function securityCheck() {
2 // Wszystkie te zmienne są dostępne wewnątrz całej funkcji
3 var securityCode = "A1B2C3";
4 let accessLevel = 5;
5 const securityChief = "Robert Muldoon";
6
7 if (accessLevel >= 5) {
8 var emergencyProtocol = "Code Red"; // zasięg funkcyjny!
9 let backupSystem = "Operational"; // zasięg blokowy
10 const safeRoom = "Bunker B"; // zasięg blokowy
11
12 console.log(securityCode); // A1B2C3 - dostępne
13 console.log(accessLevel); // 5 - dostępne
14 console.log(securityChief); // Robert Muldoon - dostępne
15 }
16
17 console.log(emergencyProtocol); // Code Red - dostępne mimo że zdefiniowane w bloku if
18 // console.log(backupSystem); // ReferenceError - zmienna ma zasięg blokowy
19 // console.log(safeRoom); // ReferenceError - zmienna ma zasięg blokowy
20}
21
22securityCheck();Zasięg blokowy
Zasięg blokowy został wprowadzony w ES6 (ES2015) wraz z nowymi słowami kluczowymi let i const. Zmienne zdefiniowane za pomocą let i const wewnątrz bloku kodu (ograniczonego nawiasami klamrowymi {}) są dostępne tylko wewnątrz tego bloku.
1function monitorDinosaurBehavior() {
2 let dangerLevel = 0;
3
4 // Blok if - tworzy nowy zasięg
5 if (true) {
6 // Zasięg blokowy - zmienne dostępne tylko wewnątrz tego bloku
7 let behavior = "Spokojne";
8 const vitals = { heartRate: 80, temperature: 38 };
9
10 // Modyfikacja zmiennej z zewnętrznego zasięgu
11 dangerLevel = behavior === "Agresywne" ? 5 : 1;
12
13 console.log(behavior); // Spokojne - dostępne
14 console.log(vitals); // { heartRate: 80, temperature: 38 } - dostępne
15 console.log(dangerLevel); // 1 - dostępne
16 }
17
18 console.log(dangerLevel); // 1 - dostępne bo zdefiniowane w szerszym zasięgu
19 // console.log(behavior); // ReferenceError - zmienna ma zasięg blokowy
20 // console.log(vitals); // ReferenceError - zmienna ma zasięg blokowy
21
22 // Blok for - również tworzy nowy zasięg
23 for (let i = 0; i < 5; i++) {
24 // 'i' ma zasięg blokowy, dostępne tylko wewnątrz pętli
25 const sensorId = `Sensor-${i}`;
26 console.log(sensorId);
27 }
28
29 // console.log(i); // ReferenceError - 'i' ma zasięg blokowy
30 // console.log(sensorId); // ReferenceError - zmienna ma zasięg blokowy
31}
32
33monitorDinosaurBehavior();Zasięg blokowy jest jak poszczególne zagrody w naszym parku - każda zagroda ma własne zasady i dostęp, a wyposażenie przypisane do jednej zagrody nie jest dostępne w innych zagrodach.
Różnica między var, let i const
Teraz możemy lepiej zrozumieć różnice między tymi trzema słowami kluczowymi:
var:- Ma zasięg funkcyjny lub globalny, ale nie blokowy
- Może być redeklarowana wielokrotnie
- Może być modyfikowana
- Jest hoistowana (wynoszona) z przypisaniem wartości
undefined
let:- Ma zasięg blokowy
- Nie może być redeklarowana w tym samym zasięgu
- Może być modyfikowana
- Jest hoistowana bez przypisania wartości (temporal dead zone)
const:- Ma zasięg blokowy
- Nie może być redeklarowana w tym samym zasięgu
- Nie może być modyfikowana (ale właściwości obiektów mogą być modyfikowane)
- Jest hoistowana bez przypisania wartości (temporal dead zone)
1function demonstrateVariables() {
2 // var
3 var dinosaur = "T-Rex";
4 var dinosaur = "Velociraptor"; // OK - można redeklarować
5 dinosaur = "Triceratops"; // OK - można modyfikować
6
7 // let
8 let park = "Jurassic Park";
9 // let park = "Dino World"; // Błąd - nie można redeklarować
10 park = "Jurassic World"; // OK - można modyfikować
11
12 // const
13 const island = "Isla Nublar";
14 // const island = "Isla Sorna"; // Błąd - nie można redeklarować
15 // island = "Another Island"; // Błąd - nie można modyfikować
16
17 // Ale właściwości obiektów const mogą być modyfikowane
18 const parkSystem = {
19 mainPower: true,
20 backupGenerator: false
21 };
22
23 // To jest dozwolone
24 parkSystem.mainPower = false;
25 parkSystem.backupGenerator = true;
26
27 console.log(parkSystem); // { mainPower: false, backupGenerator: true }
28}
29
30demonstrateVariables();Zasięg leksykalny i domknięcia (closures)
JavaScript wykorzystuje zasięg leksykalny, co oznacza, że funkcje mogą uzyskać dostęp do zmiennych zdefiniowanych w ich zewnętrznym zakresie.
1function initSecuritySystem() {
2 // Zmienne w zasięgu funkcji zewnętrznej
3 const systemName = "JurassicSafe";
4 let isActive = false;
5 let alertLevel = 0;
6
7 // Funkcja wewnętrzna ma dostęp do zmiennych z funkcji zewnętrznej
8 function activateSystem() {
9 isActive = true;
10 console.log(`System ${systemName} został aktywowany.`);
11 return true;
12 }
13
14 // Jeszcze jedna funkcja wewnętrzna
15 function setAlertLevel(level) {
16 alertLevel = level;
17 console.log(`System ${systemName}: poziom alertu ustawiony na ${alertLevel}`);
18 }
19
20 // Zwracamy funkcje wewnętrzne
21 return {
22 activate: activateSystem,
23 setAlert: setAlertLevel,
24 getStatus: function() {
25 return {
26 name: systemName,
27 active: isActive,
28 alertLevel: alertLevel
29 };
30 }
31 };
32}
33
34// Tworzymy instancję systemu bezpieczeństwa
35const securitySystem = initSecuritySystem();
36
37// Używamy zwróconych funkcji
38securitySystem.activate(); // System JurassicSafe został aktywowany.
39securitySystem.setAlert(3); // System JurassicSafe: poziom alertu ustawiony na 3
40console.log(securitySystem.getStatus()); // { name: "JurassicSafe", active: true, alertLevel: 3 }W powyższym przykładzie funkcje wewnętrzne tworzą domknięcie (closure) nad zmiennymi z funkcji initSecuritySystem. Nawet po zakończeniu wykonania initSecuritySystem, zwrócone funkcje nadal mają dostęp do tych zmiennych.
Domknięcia są jak zespoły bezpieczeństwa w parku - nawet gdy opuszczą centrum dowodzenia, nadal mają dostęp do kodów i protokołów, które zabrali ze sobą.
Praktyczny przykład: System zarządzania parkiem
Stwórzmy bardziej kompleksowy przykład, który demonstruje różne zasięgi zmiennych w kontekście systemu zarządzania parkiem:
1// Zmienne globalne - dostępne w całym programie
2const PARK_NAME = "Jurassic Park";
3let parkStatus = "closed";
4var totalVisitors = 0;
5
6// Funkcja IIFE (Immediately Invoked Function Expression) tworząca moduł
7const parkSystem = (function() {
8 // Zmienne prywatne - zasięg funkcyjny, niedostępne spoza modułu
9 let securityStatus = "active";
10 let powerStatus = "online";
11 const MAX_CAPACITY = 2000;
12
13 // Prywatna funkcja pomocnicza
14 function checkSystemStatus() {
15 return powerStatus === "online" && securityStatus === "active";
16 }
17
18 // Publiczne API modułu
19 return {
20 // Metoda otwierająca park dla zwiedzających
21 openPark: function() {
22 if (checkSystemStatus()) {
23 parkStatus = "open"; // Modyfikacja zmiennej globalnej
24 console.log(`${PARK_NAME} jest teraz otwarty dla zwiedzających!`);
25 return true;
26 } else {
27 console.log("Nie można otworzyć parku - systemy bezpieczeństwa nie są w pełni operacyjne.");
28 return false;
29 }
30 },
31
32 // Metoda rejestrująca nowych odwiedzających
33 registerVisitors: function(count) {
34 // Sprawdzenie pojemności parku
35 if (parkStatus !== "open") {
36 console.log("Park jest zamknięty. Nie można zarejestrować odwiedzających.");
37 return false;
38 }
39
40 // Zmienna z zasięgiem blokowym
41 const availableCapacity = MAX_CAPACITY - totalVisitors;
42
43 if (count <= availableCapacity) {
44 totalVisitors += count; // Modyfikacja zmiennej globalnej
45 console.log(`Zarejestrowano ${count} nowych odwiedzających. Łącznie: ${totalVisitors}`);
46
47 // Zasięg blokowy wewnątrz warunku
48 if (totalVisitors > MAX_CAPACITY * 0.8) {
49 const warningMessage = "Uwaga: Park zbliża się do maksymalnej pojemności!";
50 console.log(warningMessage);
51 }
52
53 return true;
54 } else {
55 console.log(`Błąd: Za dużo odwiedzających. Dostępna pojemność: ${availableCapacity}`);
56 return false;
57 }
58 },
59
60 // Metoda zamykająca park
61 closePark: function() {
62 // Funkcja lokalna z dostępem do zmiennych z szerszego zakresu
63 function evacuateVisitors() {
64 console.log(`Ewakuowanie ${totalVisitors} odwiedzających z parku...`);
65 totalVisitors = 0;
66 }
67
68 parkStatus = "closed";
69 evacuateVisitors();
70 console.log(`${PARK_NAME} został zamknięty.`);
71
72 return true;
73 },
74
75 // Metoda zmieniająca status systemów
76 updateSystems: function(power, security) {
77 // Dla demonstracji let vs var
78 if (power) {
79 let localMessage = "Aktualizacja systemu zasilania...";
80 console.log(localMessage);
81 powerStatus = power;
82 }
83
84 if (security) {
85 var statusMessage = "Aktualizacja systemu bezpieczeństwa...";
86 console.log(statusMessage);
87 securityStatus = security;
88 }
89
90 // console.log(localMessage); // Błąd: localMessage ma zasięg blokowy
91 console.log(statusMessage); // Działa: statusMessage ma zasięg funkcyjny
92
93 return {
94 power: powerStatus,
95 security: securityStatus
96 };
97 }
98 };
99})();
100
101// Korzystanie z naszego systemu
102console.log(`Status parku przed otwarciem: ${parkStatus}`);
103parkSystem.openPark();
104console.log(`Status parku po otwarciu: ${parkStatus}`);
105
106parkSystem.registerVisitors(500);
107parkSystem.registerVisitors(1200); // Powinien pokazać ostrzeżenie o pojemności
108parkSystem.registerVisitors(400); // Powinien pokazać błąd o przekroczeniu pojemności
109
110// Aktualizacja systemów
111parkSystem.updateSystems("offline", null);
112parkSystem.openPark(); // Powinien pokazać błąd - nie można otworzyć parku
113
114// Przywrócenie systemów i zamknięcie parku
115parkSystem.updateSystems("online", "active");
116parkSystem.closePark();
117console.log(`Status parku po zamknięciu: ${parkStatus}`);
118console.log(`Liczba odwiedzających po ewakuacji: ${totalVisitors}`);
119
120// Próba dostępu do zmiennych prywatnych
121// console.log(securityStatus); // Błąd: zmienna niedostępna
122// console.log(MAX_CAPACITY); // Błąd: zmienna niedostępnaZasady dobrej praktyki
Unikaj zmiennych globalnych - podobnie jak w rzeczywistym parku, im więcej publicznych obszarów, tym trudniej je monitorować i zabezpieczyć.
Preferuj
constnadlet, aletnadvar- większość zmiennych nie powinna zmieniać swoich wartości, a jeśli już, to powinny mieć jak najmniejszy zasięg.Używaj zasięgu blokowego - ograniczaj widoczność zmiennych do najmniejszego możliwego zakresu.
Stosuj wzorzec modułu - enkapsuluj zmienne i funkcje w modułach, udostępniając tylko niezbędne API.
Bądź świadomy domknięć - domknięcia są potężnym narzędziem, ale mogą prowadzić do wycieków pamięci, jeśli są używane nieprawidłowo.
Podsumowanie
Zasięg zmiennych w JavaScript jest jak system stref dostępu w Parku Jurajskim:
- Zasięg globalny - jak publiczne obszary parku, dostępne dla wszystkich
- Zasięg funkcyjny - jak strefy zastrzeżone dla określonych pracowników
- Zasięg blokowy - jak poszczególne zagrody i laboratoria z własnym systemem dostępu
Zrozumienie zasięgu zmiennych pozwala nam pisać lepiej zorganizowany, bardziej bezpieczny i przewidywalny kod - podobnie jak dobre zarządzanie strefami w parku pełnym niebezpiecznych dinozaurów zwiększa bezpieczeństwo wszystkich.
W jednej z kolejnych lekcji zagłębimy się w temat hoistingu (wynoszenia), który jest ściśle związany z zasięgiem zmiennych i ma istotny wpływ na sposób działania kodu JavaScript.
Kod do tej lekcji: index.js
1// Zasięg zmiennych - Park Jurajski
2console.log("Laboratorium Zasięgów Zmiennych");
3console.log("Zrozumienie scope w JavaScript\n");
4
5// ===========================================
6// 1. ZASIĘG GLOBALNY
7// ===========================================
8console.log("=== 1. Zasięg globalny ===");
9
10const parkName = "Jurassic Park"; // Zmienna globalna
11let totalDinosaurs = 0; // Zmienna globalna
12
13function addDinosaur(name) {
14 totalDinosaurs++; // Dostęp do zmiennej globalnej
15 console.log(`Dodano ${name}. Łącznie dinozaurów: ${totalDinosaurs}`);
16 console.log(` W parku: ${parkName}`);
17}
18
19addDinosaur("T-Rex");
20addDinosaur("Velociraptor");
21addDinosaur("Triceratops");
22
23console.log(`\nPark ${parkName} ma ${totalDinosaurs} dinozaurów`);
24
25// ===========================================
26// 2. ZASIĘG FUNKCYJNY
27// ===========================================
28console.log("\n=== 2. Zasięg funkcyjny ===");
29
30function feedDinosaur(dinoName) {
31 const foodAmount = 50; // Zmienna lokalna funkcji
32 const message = `Karmienie ${dinoName} (porcja: ${foodAmount}kg)`;
33
34 console.log(`${message}`);
35 return foodAmount;
36}
37
38feedDinosaur("T-Rex");
39feedDinosaur("Velociraptor");
40
41// console.log(foodAmount); // ERROR: foodAmount is not defined
42// console.log(message); // ERROR: message is not defined
43
44// ===========================================
45// 3. ZASIĘG BLOKOWY (let & const)
46// ===========================================
47console.log("\n=== 3. Zasięg blokowy (let & const) ===");
48
49function checkSecurity(sector) {
50 console.log(`\nSprawdzanie zabezpieczeń sektora ${sector}`);
51
52 if (sector === "A") {
53 let dangerLevel = "HIGH"; // Zmienna blokowa
54 const dinosaurType = "T-Rex"; // Zmienna blokowa
55
56 console.log(` Poziom zagrożenia: ${dangerLevel}`);
57 console.log(` Typ dinozaura: ${dinosaurType}`);
58 }
59
60 // console.log(dangerLevel); // ERROR: dangerLevel is not defined
61 // console.log(dinosaurType); // ERROR: dinosaurType is not defined
62
63 console.log(` Sprawdzenie sektora ${sector} zakończone`);
64}
65
66checkSecurity("A");
67checkSecurity("B");
68
69// Przykład z pętlą for
70console.log("\nPętla z let:");
71for (let i = 0; i < 3; i++) {
72 console.log(` Iteracja ${i + 1}`);
73}
74// console.log(i); // ERROR: i is not defined
75
76// ===========================================
77// 4. var vs let vs const
78// ===========================================
79console.log("\n=== 4. Różnice: var vs let vs const ===");
80
81function demonstrateScope() {
82 console.log("\nDemonstracja zasięgów:");
83
84 // var - zasięg funkcyjny (stary sposób)
85 if (true) {
86 var dinoVar = "T-Rex (var)";
87 let dinoLet = "Velociraptor (let)";
88 const dinoConst = "Triceratops (const)";
89
90 console.log(` W bloku - var: ${dinoVar}`);
91 console.log(` W bloku - let: ${dinoLet}`);
92 console.log(` W bloku - const: ${dinoConst}`);
93 }
94
95 console.log(`\n Poza blokiem - var: ${dinoVar}`); // Działa!
96 // console.log(` Poza blokiem - let: ${dinoLet}`); // ERROR
97 // console.log(` Poza blokiem - const: ${dinoConst}`); // ERROR
98}
99
100demonstrateScope();
101
102// ===========================================
103// 5. CLOSURE (DOMKNIĘCIA)
104// ===========================================
105console.log("\n=== 5. Closure (domknięcia) ===");
106
107function createDinosaurCounter(startCount = 0) {
108 let count = startCount; // Zmienna prywatna
109
110 return {
111 add: function(name) {
112 count++;
113 console.log(`Dodano ${name}. Licznik: ${count}`);
114 },
115 remove: function(name) {
116 if (count > 0) {
117 count--;
118 console.log(`Usunięto ${name}. Licznik: ${count}`);
119 }
120 },
121 getCount: function() {
122 return count;
123 }
124 };
125}
126
127const sectorA = createDinosaurCounter(5);
128const sectorB = createDinosaurCounter(0);
129
130console.log("\nSektor A:");
131sectorA.add("T-Rex");
132sectorA.add("Velociraptor");
133console.log(`Łącznie w sektorze A: ${sectorA.getCount()}`);
134
135console.log("\nSektor B:");
136sectorB.add("Triceratops");
137console.log(`Łącznie w sektorze B: ${sectorB.getCount()}`);
138
139// ===========================================
140// 6. ZAGNIEŻDŻONE FUNKCJE
141// ===========================================
142console.log("\n=== 6. Zagnieżdżone funkcje i scope ===");
143
144function managePark() {
145 const parkName = "Isla Nublar";
146 let visitors = 1000;
147
148 function openPark() {
149 console.log(`\n${parkName} otwarty dla ${visitors} odwiedzających`);
150
151 function welcomeVisitors() {
152 visitors += 50;
153 console.log(` Powitanie nowych gości. Teraz: ${visitors}`);
154 }
155
156 welcomeVisitors();
157 }
158
159 function closePark() {
160 console.log(`\nZamykanie ${parkName}`);
161 console.log(` Dzisiejszych odwiedzających: ${visitors}`);
162 }
163
164 openPark();
165 closePark();
166}
167
168managePark();
169
170// ===========================================
171// 7. SHADOWING (PRZESŁANIANIE)
172// ===========================================
173console.log("\n=== 7. Shadowing (przesłanianie zmiennych) ===");
174
175const dinosaur = "T-Rex (globalny)";
176
177function checkDinosaur() {
178 const dinosaur = "Velociraptor (funkcja)"; // Przesłania globalną
179 console.log(`W funkcji: ${dinosaur}`);
180
181 if (true) {
182 const dinosaur = "Triceratops (blok)"; // Przesłania funkcyjną
183 console.log(` W bloku: ${dinosaur}`);
184 }
185
186 console.log(` Po bloku: ${dinosaur}`);
187}
188
189console.log(`Globalnie: ${dinosaur}`);
190checkDinosaur();
191console.log(`Ponownie globalnie: ${dinosaur}`);
192
193// ===========================================
194// 8. LEXICAL SCOPE (ZASIĘG LEKSYKALNY)
195// ===========================================
196console.log("\n=== 8. Lexical scope ===");
197
198const habitat = "Tropikalny las";
199
200function outerFunction() {
201 const temperature = 28;
202
203 function innerFunction() {
204 const humidity = 80;
205
206 // Dostęp do wszystkich zmiennych z nadrzędnych zasięgów
207 console.log(`Środowisko: ${habitat}`);
208 console.log(` Temperatura: ${temperature}°C`);
209 console.log(` Wilgotność: ${humidity}%`);
210 }
211
212 innerFunction();
213}
214
215outerFunction();
216
217// ===========================================
218// 9. PRAKTYCZNY PRZYKŁAD - SYSTEM KARMIENIA
219// ===========================================
220console.log("\n=== 9. System karmienia - przykład praktyczny ===");
221
222function createFeedingSystem() {
223 const feedingSchedule = [];
224 let lastFeedingTime = null;
225
226 return {
227 scheduleFeed: function(dinoName, time) {
228 const entry = { dino: dinoName, time: time, completed: false };
229 feedingSchedule.push(entry);
230 console.log(`Zaplanowano karmienie: ${dinoName} o ${time}`);
231 },
232
233 completeFeed: function(dinoName) {
234 const entry = feedingSchedule.find(e => e.dino === dinoName && !e.completed);
235 if (entry) {
236 entry.completed = true;
237 lastFeedingTime = new Date().toLocaleTimeString();
238 console.log(`Nakarmiono ${dinoName} o ${lastFeedingTime}`);
239 } else {
240 console.log(`Brak zaplanowanego karmienia dla ${dinoName}`);
241 }
242 },
243
244 getReport: function() {
245 console.log("\nRAPORT KARMIENIA:");
246 console.log(` Ostatnie karmienie: ${lastFeedingTime || "Brak"}`);
247 console.log(` Zaplanowane karmienia: ${feedingSchedule.length}`);
248
249 const pending = feedingSchedule.filter(e => !e.completed);
250 if (pending.length > 0) {
251 console.log("\n Oczekujące:");
252 pending.forEach(e => {
253 console.log(` - ${e.dino} o ${e.time}`);
254 });
255 }
256 }
257 };
258}
259
260const feedingSystem = createFeedingSystem();
261
262feedingSystem.scheduleFeed("T-Rex", "08:00");
263feedingSystem.scheduleFeed("Velociraptor", "10:00");
264feedingSystem.scheduleFeed("Triceratops", "12:00");
265
266feedingSystem.completeFeed("T-Rex");
267feedingSystem.completeFeed("Velociraptor");
268
269feedingSystem.getReport();
270
271// ===========================================
272// 10. BEST PRACTICES
273// ===========================================
274console.log("\n=== 10. Best practices ===");
275
276// DOBRE: Używaj const dla wartości, które się nie zmieniają
277const MAX_DINOSAURS = 50;
278console.log(`Maksymalna liczba dinozaurów: ${MAX_DINOSAURS}`);
279
280// DOBRE: Używaj let dla wartości zmiennych
281let currentDinoCount = 15;
282currentDinoCount += 5;
283console.log(`Aktualna liczba: ${currentDinoCount}`);
284
285// ZŁE: Unikaj var (stary sposób)
286// var oldStyle = "Niepolecane";
287
288// DOBRE: Ograniczaj zasięg zmiennych do minimum
289function goodScope() {
290 const onlyHere = "Dostępne tylko tutaj";
291 return onlyHere;
292}
293
294console.log("\nGratulacje! Opanowałeś zasięg zmiennych!");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óra deklaracja zmiennej jest najlepsza dla stałej wartości gatunku dinozaura?
2. Co zwróci następujący kod: String(65000000)?
3. Dr. Wu organizuje dane w laboratorium. Które dopasowanie rodzaju danych do typu JavaScript jest NIEPOPRAWNE?
Zadania praktyczne w grze
- Edytor kodu
Dane z formularza zawsze są tekstem: const inputWeight = '6200', const inputLength = '9.5' i const inputTeeth = '800'. Zamień je na liczby: numWeight przez Number(), numLength przez parseFloat() i numTeeth przez parseInt(). Potem zapisz w weightText wartość numWeight z powrotem jako tekst przez String(). Wyświetl w konsoli wszystkie cztery wartości razem z ich typem (typeof).