W Parku Jurajskim zespół pracowników wykonuje różne wyspecjalizowane zadania: dr Wu zajmuje się genetyką, zespół bezpieczeństwa monitoruje ogrodzenia, a weterynarze dbają o zdrowie dinozaurów. Każdy specjalista wykonuje określone zadania, gdy jest o to proszony, bez konieczności tłumaczenia za każdym razem, jak dokładnie ma to zrobić.
W JavaScript funkcje działają podobnie - są to bloki kodu zaprojektowane do wykonywania określonych zadań. Funkcje można zdefiniować raz i wywołać wielokrotnie, co czyni kod bardziej modułowym, czytelnym i łatwiejszym w utrzymaniu.
W JavaScript istnieje kilka sposobów definiowania funkcji. Zacznijmy od najbardziej podstawowej - deklaracji funkcji:
1// Podstawowa składnia deklaracji funkcji
2function functionName(parameter1, parameter2, ...) {
3 // Blok kodu do wykonania
4 return value; // Opcjonalna instrukcja zwracająca wartość
5}W kontekście Parku Jurajskiego, moglibyśmy stworzyć funkcję do sprawdzania bezpieczeństwa wybiegu:
1// Funkcja sprawdzająca bezpieczeństwo wybiegu
2function checkEnclosureSafety(powerLevel, fenceCondition, dinoSpecies) {
3 // Warunki bezpieczeństwa zależne od gatunku
4 let minPowerLevel;
5
6 if (dinoSpecies === "Tyranozaur" || dinoSpecies === "Velociraptor") {
7 minPowerLevel = 90; // Dla niebezpiecznych drapieżników wymagamy wysokiego poziomu zasilania
8 } else if (dinoSpecies === "Dilofozaur" || dinoSpecies === "Karnotaur") {
9 minPowerLevel = 75; // Dla mniejszych drapieżników
10 } else {
11 minPowerLevel = 50; // Dla roślinożerców
12 }
13
14 // Sprawdzenie warunków bezpieczeństwa
15 if (powerLevel < minPowerLevel) {
16 return "NIEBEZPIECZNE: Zbyt niski poziom zasilania dla tego gatunku!";
17 }
18
19 if (fenceCondition !== "sprawne") {
20 return "NIEBEZPIECZNE: Ogrodzenie wymaga naprawy!";
21 }
22
23 return "BEZPIECZNE: Wybieg spełnia wszystkie wymogi bezpieczeństwa.";
24}
25
26// Przykłady użycia funkcji
27let tRexInspectionResult = checkEnclosureSafety(85, "sprawne", "Tyranozaur");
28console.log(`Wybieg T-Rex: ${tRexInspectionResult}`); // "Wybieg T-Rex: NIEBEZPIECZNE: Zbyt niski poziom zasilania dla tego gatunku!"
29
30let triceratopsInspectionResult = checkEnclosureSafety(60, "sprawne", "Triceratops");
31console.log(`Wybieg Triceratops: ${triceratopsInspectionResult}`); // "Wybieg Triceratops: BEZPIECZNE: Wybieg spełnia wszystkie wymogi bezpieczeństwa."Innym sposobem definiowania funkcji jest użycie wyrażenia funkcyjnego, gdzie funkcja jest przypisana do zmiennej:
1// Wyrażenie funkcyjne
2const functionName = function(parameter1, parameter2, ...) {
3 // Blok kodu do wykonania
4 return value; // Opcjonalnie
5};Przykład z Parku Jurajskiego:
1// Funkcja obliczająca dzienne zapotrzebowanie na pokarm
2const calculateDailyFoodRequirement = function(species, weight, age) {
3 let baseFactor;
4
5 // Określenie podstawowego wskaźnika w zależności od diety
6 if (["Tyranozaur", "Velociraptor", "Spinozaur"].includes(species)) {
7 baseFactor = 0.10; // 10% wagi ciała dla mięsożerców
8 } else if (["Allozaur", "Karnotaur", "Dilofozaur"].includes(species)) {
9 baseFactor = 0.08; // 8% wagi ciała dla mniejszych mięsożerców
10 } else {
11 baseFactor = 0.15; // 15% wagi ciała dla roślinożerców (jedzą więcej, ale mniej kaloryczny pokarm)
12 }
13
14 // Korekta ze względu na wiek (młode osobniki jedzą proporcjonalnie więcej)
15 let ageFactor = age < 5 ? 1.5 : age < 10 ? 1.2 : 1.0;
16
17 // Obliczenie dziennego zapotrzebowania na pokarm w kg
18 let dailyRequirement = weight * baseFactor * ageFactor;
19
20 return Math.round(dailyRequirement * 10) / 10; // Zaokrąglenie do 1 miejsca po przecinku
21};
22
23// Przykłady użycia
24console.log(`Dzienne zapotrzebowanie na pokarm dla młodego T-Rexa: ${calculateDailyFoodRequirement("Tyranozaur", 2000, 3)} kg`);
25// "Dzienne zapotrzebowanie na pokarm dla młodego T-Rexa: 300 kg"
26
27console.log(`Dzienne zapotrzebowanie na pokarm dla dorosłego Stegozaura: ${calculateDailyFoodRequirement("Stegozaur", 5000, 12)} kg`);
28// "Dzienne zapotrzebowanie na pokarm dla dorosłego Stegozaura: 750 kg"Funkcje strzałkowe to bardziej zwięzły sposób zapisywania funkcji, wprowadzony w ES6:
1// Składnia funkcji strzałkowej
2const functionName = (parameter1, parameter2, ...) => {
3 // Blok kodu
4 return value;
5};
6
7// Dla prostych funkcji z jednym wyrażeniem, można pominąć klamry i słowo return
8const simpleSum = (a, b) => a + b;Przykład zastosowania w Parku Jurajskim:
1// Funkcja strzałkowa do klasyfikowania dinozaurów
2const classifyDinosaur = (species, length, speed) => {
3 // Klasyfikacja zagrożenia na podstawie gatunku, rozmiaru i prędkości
4 if (["Tyranozaur", "Spinozaur"].includes(species) && length > 10) {
5 return "Najwyższe zagrożenie - Klasa A";
6 } else if (["Velociraptor", "Dilofozaur"].includes(species) && speed > 30) {
7 return "Wysokie zagrożenie - Klasa B";
8 } else if (["Allozaur", "Karnotaur"].includes(species)) {
9 return "Średnie zagrożenie - Klasa C";
10 } else if (species.includes("raptor") || speed > 40) {
11 return "Podwyższone zagrożenie - Klasa D";
12 } else {
13 return "Niskie zagrożenie - Klasa E";
14 }
15};
16
17// Proste funkcje strzałkowe bez bloku kodu
18const isPredator = species => ["Tyranozaur", "Velociraptor", "Spinozaur", "Allozaur", "Karnotaur", "Dilofozaur"].includes(species);
19const estimateSpeed = (limbLength, mass) => Math.round(limbLength * 0.7 * (100 / mass));
20
21// Przykłady użycia
22console.log(classifyDinosaur("Tyranozaur", 12, 27)); // "Najwyższe zagrożenie - Klasa A"
23console.log(classifyDinosaur("Gallimim", 2, 45)); // "Podwyższone zagrożenie - Klasa D"
24console.log(isPredator("Stegozaur")); // false
25console.log(estimateSpeed(2.5, 200)); // 9Funkcje mogą przyjmować parametry, które są zmiennymi lokalnymi dostępnymi wewnątrz funkcji:
Od ES6 możemy definiować wartości domyślne dla parametrów:
1function setIncubatorTemperature(species, temperature = 37.5) {
2 console.log(`Ustawiono temperaturę inkubatora dla jaj ${species} na ${temperature}°C`);
3 // Dalszy kod...
4}
5
6setIncubatorTemperature("Velociraptor"); // "Ustawiono temperaturę inkubatora dla jaj Velociraptor na 37.5°C"
7setIncubatorTemperature("Triceratops", 36.2); // "Ustawiono temperaturę inkubatora dla jaj Triceratops na 36.2°C"Pozwalają na przekazanie nieokreślonej liczby argumentów jako tablicy:
1function monitorDinosaurs(...ids) {
2 console.log(`Monitorowanie ${ids.length} dinozaurów...`);
3
4 for (let id of ids) {
5 console.log(`Sprawdzanie dinozaura #${id}...`);
6 // Kod monitorowania...
7 }
8
9 return `Zakończono monitorowanie ${ids.length} dinozaurów.`;
10}
11
12console.log(monitorDinosaurs(101, 102, 103, 104, 105));
13// Wyświetli:
14// "Monitorowanie 5 dinozaurów..."
15// "Sprawdzanie dinozaura #101..."
16// "Sprawdzanie dinozaura #102..."
17// "Sprawdzanie dinozaura #103..."
18// "Sprawdzanie dinozaura #104..."
19// "Sprawdzanie dinozaura #105..."
20// "Zakończono monitorowanie 5 dinozaurów."Funkcje mogą zwracać wartości za pomocą instrukcji
return:1function analyzeDnaSample(sample) {
2 // Kod analizy próbki...
3
4 if (!sample || sample.length < 10) {
5 return { success: false, message: "Niewystarczająca ilość materiału genetycznego." };
6 }
7
8 // Symulacja analizy
9 const species = ["Tyranozaur", "Triceratops", "Velociraptor", "Stegozaur", "Brontozaur"];
10 const randomIndex = Math.floor(Math.random() * species.length);
11
12 return {
13 success: true,
14 species: species[randomIndex],
15 dnaPurity: Math.round(Math.random() * 50 + 50), // 50-100%
16 completeness: Math.round(Math.random() * 40 + 60), // 60-100%
17 message: "Analiza zakończona pomyślnie."
18 };
19}
20
21const analysisResult = analyzeDnaSample("ACGTAAGTCCTGAT");
22console.log(analysisResult);
23// Przykładowy wynik:
24// {
25// success: true,
26// species: "Velociraptor",
27// dnaPurity: 87,
28// completeness: 75,
29// message: "Analiza zakończona pomyślnie."
30// }
31
32if (analysisResult.success) {
33 console.log(`Zidentyfikowano DNA ${analysisResult.species}a o czystości ${analysisResult.dnaPurity}%`);
34} else {
35 console.log(`Błąd analizy: ${analysisResult.message}`);
36}Zmienne zdefiniowane wewnątrz funkcji są lokalne dla tej funkcji i nie są dostępne na zewnątrz:
1function prepareJurassicIncident() {
2 // Zmienna lokalna, niedostępna poza funkcją
3 let secretSystemCode = "TRex1993";
4 console.log(`Kod wygenerowany wewnątrz funkcji: ${secretSystemCode}`);
5 return "Incydent przygotowany.";
6}
7
8prepareJurassicIncident();
9// Próba dostępu do zmiennej lokalnej poza funkcją spowoduje błąd
10// console.log(secretSystemCode); // ReferenceError: secretSystemCode is not defined
11
12// Zmienne zdefiniowane na zewnątrz funkcji są dostępne wewnątrz
13let jurassicParkLocation = "Isla Nublar";
14
15function displayParkInfo() {
16 // Dostęp do zmiennej zewnętrznej
17 console.log(`Park Jurajski znajduje się na wyspie: ${jurassicParkLocation}`);
18
19 // Zmienna lokalna
20 let dinosaurCount = 200;
21 console.log(`Aktualna liczba dinozaurów: ${dinosaurCount}`);
22}
23
24displayParkInfo();
25// console.log(dinosaurCount); // ReferenceError: dinosaurCount is not definedFunkcje mogą być zdefiniowane wewnątrz innych funkcji:
1function conductScientificResearch(species) {
2 console.log(`Rozpoczęcie badań naukowych nad gatunkiem: ${species}`);
3
4 // Funkcja zagnieżdżona - dostępna tylko wewnątrz conductScientificResearch
5 function analyzeSample() {
6 console.log(`Analizowanie próbki DNA ${species}a...`);
7 return "Analiza kompletna";
8 }
9
10 // Inna funkcja zagnieżdżona
11 function simulateGrowth() {
12 console.log(`Symulowanie wzrostu i rozwoju ${species}a...`);
13 return "Symulacja ukończona";
14 }
15
16 // Wywołanie funkcji zagnieżdżonych
17 const analysisResult = analyzeSample();
18 const simulationResult = simulateGrowth();
19
20 return {
21 species,
22 analysisResult,
23 simulationResult,
24 researchDate: new Date().toISOString()
25 };
26}
27
28const researchReport = conductScientificResearch("Velociraptor");
29console.log(researchReport);
30// Funkcje zagnieżdżone nie są dostępne poza funkcją zewnętrzną
31// analyzeSample(); // ReferenceError: analyzeSample is not definedW JavaScript funkcje są obiektami pierwszej klasy, co oznacza, że mogą być przekazywane jako argumenty do innych funkcji lub zwracane przez funkcje:
1// Funkcja przyjmująca inną funkcję jako parametr
2function monitorEnclosure(enclosureId, alarmFunction) {
3 console.log(`Monitorowanie wybiegu #${enclosureId}`);
4
5 // Symulacja problemu
6 const anomalyDetected = Math.random() > 0.7;
7
8 if (anomalyDetected) {
9 // Wywołanie przekazanej funkcji w przypadku wykrycia problemu
10 alarmFunction(`Anomalia wykryta w wybiegu #${enclosureId}!`);
11 }
12
13 return { enclosureId, status: anomalyDetected ? "Anomalia" : "Normalny" };
14}
15
16// Funkcje, które mogą być przekazane jako argument
17function soundAlarm(message) {
18 console.log(`🔊 ALARM DŹWIĘKOWY: ${message}`);
19}
20
21function visualAlarm(message) {
22 console.log(`🚨 ALARM WIZUALNY: ${message}`);
23}
24
25function staffNotifications(message) {
26 console.log(`📱 POWIADOMIENIE SMS: ${message}`);
27}
28
29// Użycie funkcji wyższego rzędu z różnymi funkcjami alarmowymi
30monitorEnclosure(1, soundAlarm);
31monitorEnclosure(2, visualAlarm);
32monitorEnclosure(3, staffNotifications);
33
34// Możemy także przekazać funkcję anonimową
35monitorEnclosure(4, function(message) {
36 console.log(`⚠️ PROCEDURA AWARYJNA: ${message}`);
37 console.log("Uruchamianie protokołu ewakuacji...");
38});
39
40// Lub funkcję strzałkową
41monitorEnclosure(5, message => console.log(`🔍 RAPORT DIAGNOSTYCZNY: ${message}`));1// Funkcja tworząca i zwracająca inną funkcję
2function createSpeciesMonitor(species) {
3 // Zwracamy nową funkcję dostosowaną do konkretnego gatunku
4 return function(action) {
5 const actionTime = new Date().toLocaleTimeString();
6 console.log(`[${actionTime}] ${species}: ${action}`);
7
8 // Dodatkowa logika zależna od gatunku
9 if (["Tyranozaur", "Velociraptor", "Dilofozaur"].includes(species) && action.includes("blisko ogrodzenia")) {
10 console.log(`⚠️ OSTRZEŻENIE! Niebezpieczny drapieżnik ${species} blisko ogrodzenia!`);
11 }
12 };
13}
14
15// Tworzenie monitorów dla różnych gatunków
16const tRexMonitor = createSpeciesMonitor("Tyranozaur");
17const triceratopsMonitor = createSpeciesMonitor("Triceratops");
18
19// Używanie zwróconych funkcji
20tRexMonitor("Porusza się w kierunku południowym");
21tRexMonitor("Zbliża się blisko ogrodzenia");
22triceratopsMonitor("Żeruje w północnej części wybiegu");IIFE (Immediately Invoked Function Expression) to funkcja, która jest zdefiniowana i wywołana natychmiast:
1// Struktura IIFE
2(function() {
3 // Kod funkcji...
4})();
5
6// IIFE z parametrami
7(function(name) {
8 console.log(`Inicjalizacja systemu: ${name}`);
9})("Park Jurajski");IIFE są przydatne do tworzenia prywatnego zakresu i unikania zanieczyszczania globalnego obiektu:
1// Inicjalizacja systemu Parku Jurajskiego za pomocą IIFE
2const jurassicParkSystem = (function() {
3 // Prywatne zmienne, niedostępne z zewnątrz
4 const securityCodes = {
5 mainGates: "GATES1993",
6 laboratory: "INGEN2015",
7 powerSystem: "NEDRY1992"
8 };
9
10 let systemStatus = "offline";
11 let securityLevel = 0;
12
13 // Prywatne funkcje
14 function validateCode(providedCode, requiredCode) {
15 return providedCode === requiredCode;
16 }
17
18 // Publiczny interfejs - tylko te funkcje będą dostępne na zewnątrz
19 return {
20 startSystem: function() {
21 systemStatus = "online";
22 securityLevel = 3;
23 console.log("System Parku Jurajskiego uruchomiony.");
24 return true;
25 },
26
27 checkStatus: function() {
28 return {
29 status: systemStatus,
30 securityLevel,
31 updateTime: new Date().toISOString()
32 };
33 },
34
35 grantAccess: function(area, code) {
36 if (!validateCode(code, securityCodes[area])) {
37 console.log(`Odmowa dostępu do obszaru: ${area}`);
38 return false;
39 }
40 console.log(`Dostęp przyznany do obszaru: ${area}`);
41 return true;
42 }
43 };
44})();
45
46// Używanie publicznego interfejsu
47jurassicParkSystem.startSystem();
48console.log(jurassicParkSystem.checkStatus());
49jurassicParkSystem.grantAccess("mainGates", "GATES1993"); // true
50jurassicParkSystem.grantAccess("laboratory", "nieprawidłowy kod"); // false
51
52// Próba dostępu do prywatnych zmiennych nie powiedzie się
53// console.log(jurassicParkSystem.securityCodes); // undefined
54// console.log(jurassicParkSystem.validateCode); // undefinedRekurencja to technika, w której funkcja wywołuje samą siebie:
1// Funkcja rekurencyjna symulująca reprodukcję dinozaurów
2function simulateReproduction(initialPopulation, yearsAhead, growthRate = 1.5) {
3 // Warunek zakończenia rekurencji
4 if (yearsAhead <= 0) {
5 return initialPopulation;
6 }
7
8 // Obliczenie nowej populacji po jednym roku
9 const newPopulation = Math.round(initialPopulation * growthRate);
10
11 console.log(`Rok ${yearsAhead} do końca symulacji. Populacja: ${newPopulation}`);
12
13 // Wywołanie rekurencyjne z nową populacją i zmniejszonym licznikiem lat
14 return simulateReproduction(newPopulation, yearsAhead - 1, growthRate);
15}
16
17// Początkowa populacja: 2 dinozaury, symulacja na 5 lat do przodu
18const finalPopulation = simulateReproduction(2, 5);
19console.log(`Końcowa populacja po 5 latach: ${finalPopulation}`);
20
21// Wynik:
22// Rok 5 do końca symulacji. Populacja: 3
23// Rok 4 do końca symulacji. Populacja: 5
24// Rok 3 do końca symulacji. Populacja: 8
25// Rok 2 do końca symulacji. Populacja: 12
26// Rok 1 do końca symulacji. Populacja: 18
27// Końcowa populacja po 5 latach: 27Ważne jest, aby zawsze mieć warunek zakończenia rekurencji, aby uniknąć nieskończonych wywołań, które mogą spowodować błąd przepełnienia stosu.
Hoisting to zachowanie JavaScript, które "przenosi" deklaracje na górę ich zakresu:
1// Możemy wywołać funkcję przed jej deklaracją dzięki hoistingowi
2console.log(checkParkSafety()); // "Park bezpieczny"
3
4// Deklaracja funkcji jest przeniesiona na górę
5function checkParkSafety() {
6 return "Park bezpieczny";
7}
8
9// Jednak wyrażenia funkcyjne nie są w pełni hoistowane
10// console.log(calculateRisk()); // Error: calculateRisk is not a function
11
12// Tylko deklaracja zmiennej jest hoistowana, ale nie jej wartość
13var calculateRisk = function() {
14 return "Niskie ryzyko";
15};
16
17// Podobnie z let i const - są hoistowane, ale nie inicjalizowane
18// console.log(analyzeData); // ReferenceError: Cannot access 'analyzeData' before initialization
19let analyzeData = function() {
20 return "Analiza kompletna";
21};Domknięcie powstaje, gdy funkcja wewnętrzna ma dostęp do zakresu funkcji zewnętrznej, nawet po jej zakończeniu:
1function createDinosaurCounter(roomName) {
2 let dinosaurCount = 0;
3
4 // Funkcja wewnętrzna tworzy domknięcie
5 function updateCounter(change) {
6 dinosaurCount += change;
7 console.log(`${roomName}: Aktualna liczba dinozaurów: ${dinosaurCount}`);
8 return dinosaurCount;
9 }
10
11 return {
12 addDinosaur: function() {
13 return updateCounter(1);
14 },
15 removeDinosaur: function() {
16 return updateCounter(-1);
17 },
18 getDinosaurCount: function() {
19 return dinosaurCount;
20 }
21 };
22}
23
24// Tworzenie dwóch niezależnych liczników dla różnych pomieszczeń
25const enclosureACounter = createDinosaurCounter("Wybieg A");
26const enclosureBCounter = createDinosaurCounter("Wybieg B");
27
28enclosureACounter.addDinosaur(); // "Wybieg A: Aktualna liczba dinozaurów: 1"
29enclosureACounter.addDinosaur(); // "Wybieg A: Aktualna liczba dinozaurów: 2"
30enclosureBCounter.addDinosaur(); // "Wybieg B: Aktualna liczba dinozaurów: 1"
31enclosureACounter.removeDinosaur(); // "Wybieg A: Aktualna liczba dinozaurów: 1"Domknięcia są niezwykle przydatne w tworzeniu funkcji fabrycznych, enkapsulacji danych, i w realizacji wzorców projektowych.
Jedna funkcja, jedno zadanie: Funkcje powinny być zaprojektowane do wykonywania jednego, konkretnego zadania. Ułatwia to testowanie, debugowanie i utrzymanie kodu.
Opisowe nazwy funkcji: Używaj jasnych, opisowych nazw funkcji, które wskazują na ich przeznaczenie (np.
loginUser zamiast uFunc1).Ograniczenie liczby parametrów: Staraj się ograniczać liczbę parametrów. Jeśli funkcja wymaga wielu parametrów, rozważ użycie obiektu opcji:
1// Zamiast:
2function configureSecuritySystem(powerLevel, sensorSensitivity, reactionTime, operationMode, notifications) {
3 //
4}
5
6// Użyj:
7function configureSecuritySystem(options) {
8 const {
9 powerLevel = 100,
10 sensorSensitivity = "wysoka",
11 reactionTime = 5,
12 operationMode = "automatyczny",
13 notifications = true
14 } = options;
15
16 //
17}
18
19// Wywołanie:
20configureSecuritySystem({
21 powerLevel: 90,
22 reactionTime: 3,
23 operationMode: "ręczny"
24});Unikanie efektów ubocznych: Staraj się, aby funkcje nie modyfikowały zmiennych poza swoim zakresem lub argumentów, które nie zostały przekazane przez referencję.
Konwencje zwracania wartości: Bądź konsekwentny w zwracaniu wartości. Unikaj funkcji, które czasami zwracają wartość, a czasami nie.
Obsługa błędów: Zawsze uwzględniaj potencjalne błędy i obsługuj je odpowiednio, używając bloków try-catch lub zwracając obiekty statusu.
1function cloneDinosaur(dna) {
2 try {
3 if (!dna || dna.length < 100) {
4 throw new Error("Niewystarczająca ilość DNA do klonowania");
5 }
6
7 // Kod klonowania...
8
9 return {
10 success: true,
11 dinosaur: { species: "Velociraptor", id: "VR-" + Math.floor(Math.random() * 1000) }
12 };
13 } catch (error) {
14 console.error(`Błąd klonowania: ${error.message}`);
15 return {
16 success: false,
17 error: error.message
18 };
19 }
20}Podobnie jak DNA dinozaurów nieustannie ewoluowało, aby dostosować się do zmieniającego się środowiska, JavaScript również przechodzi ciągły proces ewolucji. Za tym procesem stoi TC39 - komitet techniczny odpowiedzialny za rozwój języka JavaScript.
TC39 (Technical Committee 39) to grupa ekspertów, która zarządza rozwojem specyfikacji ECMAScript (oficjalnej nazwy standardu JavaScript). W skład TC39 wchodzą przedstawiciele firm takich jak Google, Mozilla, Apple, Microsoft oraz innych organizacji i niezależni eksperci.
Podobnie jak rada naukowa Parku Jurajskiego decyduje o tym, które gatunki dinozaurów będą hodowane i jak będą zarządzane, TC39 decyduje o tym, jakie nowe funkcjonalności trafią do JavaScript i w jakiej formie.
Każda nowa funkcjonalność w JavaScript przechodzi przez pięć etapów (stages), od pomysłu do implementacji:
Stage 0 - Strawman (Strach na wróble)
Najwcześniejszy etap - to jak pierwsza szkicowa wizja nowego gatunku dinozaura na papierze. Każdy może zgłosić pomysł. Nie ma żadnych formalnych wymagań, to po prostu miejsce na dzielenie się pomysłami.
Stage 1 - Proposal (Propozycja)
Komitet uznał, że pomysł jest wart rozważenia. To jak faza, gdy naukowcy Parku Jurajskiego zdecydowali, że warto poważnie rozważyć klonowanie konkretnego gatunku. Na tym etapie:
Stage 2 - Draft (Szkic)
Propozycja ma teraz wstępną specyfikację techniczną. To jak szczegółowy plan genetyczny i procedury hodowlane dla nowego dinozaura. Na tym etapie:
Stage 3 - Candidate (Kandydat)
Specyfikacja jest kompletna i czeka na feedback z implementacji. To jak pierwsze próby klonowania - mamy kompletny plan, teraz testujemy go w praktyce. Na tym etapie:
Stage 4 - Finished (Ukończona)
Propozycja jest gotowa do włączenia do oficjalnej specyfikacji ECMAScript! To jak moment, gdy nowy dinozaur pomyślnie się wykluwa i jest gotowy do prezentacji w parku. Na tym etapie:
Przyjrzyjmy się kilku fascynującym propozycjom, które mogą zmienić sposób, w jaki piszemy kod JavaScript:
Operator pipeline pozwala na łańcuchowanie operacji w bardziej czytelny sposób, podobnie jak kanały w systemie transportu wody w Parku Jurajskim:
1// Bez pipeline operator
2const result = Math.round(Math.max(5, 10, 15) * 2);
3
4// Z pipeline operator
5const result = [5, 10, 15]
6 |> Math.max
7 |> (x => x * 2)
8 |> Math.round;
9
10// Przykład z systemem bezpieczeństwa parku
11const securityStatus = fetchSensorData()
12 |> filterActiveSensors
13 |> analyzeThreatLevel
14 |> generateSecurityReport;Niezmienne (immutable) struktury danych, które mogą być porównywane przez wartość. To jak niezmienne próbki DNA - raz pobrane, nigdy się nie zmieniają:
1// Record (podobny do obiektu, ale niezmienny)
2const dinoRecord = #{
3 species: "Velociraptor",
4 age: 4,
5 enclosure: "A-7"
6};
7
8// Tuple (podobny do tablicy, ale niezmienny)
9const coordinates = #[48.8566, 2.3522];
10
11// Porównanie przez wartość
12const dino1 = #{ species: "T-Rex", age: 8 };
13const dino2 = #{ species: "T-Rex", age: 8 };
14console.log(dino1 === dino2); // true! (w zwykłych obiektach byłoby false)
15
16// Niemożliwe jest modyfikowanie
17dinoRecord.age = 5; // TypeError!Potężny mechanizm dopasowywania wzorców, który sprawia, że kod warunkowy staje się bardziej czytelny. To jak system klasyfikacji dinozaurów - możemy precyzyjnie dopasować działania do różnych typów:
1// Zamiast wielu if/else lub switch
2const handleDinosaur = (dino) => {
3 match (dino) {
4 when ({ species: "Tyrannosaurus Rex", health: health }) if (health < 50) -> {
5 return "Wezwij weterynarza dla T-Rexa!";
6 }
7 when ({ diet: "carnivore", escaped: true }) -> {
8 return "ALARM! Drapieżnik uciekł!";
9 }
10 when ({ species: "Velociraptor" }) -> {
11 return "Sprawdź zabezpieczenia wybiegu";
12 }
13 when ({ health: h }) if (h > 90) -> {
14 return "Dinozaur w doskonałej kondycji";
15 }
16 default -> {
17 return "Standardowa procedura monitoringu";
18 }
19 }
20};Dekoratory pozwalają na modyfikowanie klas i ich członków w deklaratywny sposób. To jak system tagów i czipów dla dinozaurów - dodajemy dodatkowe funkcjonalności bez modyfikowania podstawowej struktury:
1// Dekorator do logowania wywołań metod
2function log(target, propertyKey, descriptor) {
3 const originalMethod = descriptor.value;
4
5 descriptor.value = function(...args) {
6 console.log(`Wywołanie ${propertyKey} z argumentami: ${JSON.stringify(args)}`);
7 const result = originalMethod.apply(this, args);
8 console.log(`Wynik: ${result}`);
9 return result;
10 };
11
12 return descriptor;
13}
14
15class DinosaurMonitor {
16 @log
17 checkHealth(dinosaurId) {
18 // Sprawdzanie stanu zdrowia
19 return "healthy";
20 }
21
22 @log
23 feedDinosaur(dinosaurId, foodAmount) {
24 // Karmienie dinozaura
25 return "fed";
26 }
27}
28
29// Każde wywołanie metody będzie automatycznie logowane!
30const monitor = new DinosaurMonitor();
31monitor.checkHealth("TREX-001");
32// Konsola: Wywołanie checkHealth z argumentami: ["TREX-001"]
33// Konsola: Wynik: healthyJeśli chcesz być na bieżąco z ewolucją JavaScript, podobnie jak naukowcy Parku Jurajskiego monitorują ewolucję swoich dinozaurów, możesz:
Repozytorium GitHub TC39: https://github.com/tc39/proposals
TC39 Meeting Notes: https://github.com/tc39/notes
Can I Use: https://caniuse.com
Babel: https://babeljs.io
TC39 Website: https://tc39.es
Podobnie jak Park Jurajski nieustannie ewoluuje, dodając nowe gatunki i ulepszając systemy bezpieczeństwa, JavaScript także nieustannie się rozwija. Zrozumienie procesu TC39 i śledzenie nowych propozycji to jak posiadanie mapy genetycznej przyszłości języka - pozwala nam przygotować się na to, co nadchodzi, i kształtować tę przyszłość poprzez aktywny udział w społeczności.
Funkcje w JavaScript, podobnie jak wyspecjalizowane zespoły w Parku Jurajskim, pozwalają na:
Główne koncepcje dotyczące funkcji:
Poznaliśmy też mechanizm TC39 i proces rozwoju JavaScript - od propozycji Stage 0 do gotowej implementacji w Stage 4. Zrozumienie tego procesu pozwala nam być na bieżąco z ewolucją języka i przygotować się na przyszłość programowania w JavaScript.
W następnej lekcji przyjrzymy się obiektom - kluczowym strukturom danych w JavaScript, które są równie niezbędne dla organizacji naszego kodu jak mapy sektorów dla zarządzania Parkiem Jurajskim.