Kurs JavaScript i TypeScript · Moduł 2: Funkcje, tablice i obiekty
Tworzenie obiektów (literały, konstruktory)
W tej lekcji8
W Parku Jurajskim używamy obiektów JavaScript do reprezentowania wielu elementów naszego ekosystemu - od dinozaurów i ich zachowań, przez obszary parku, po dane pracowników i procedury bezpieczeństwa. Obiekty są fundamentalnym typem danych w JavaScript, umożliwiającym tworzenie złożonych struktur danych z właściwościami i metodami.
Literały obiektów
Najprostszym sposobem tworzenia obiektów w JavaScript jest użycie literału obiektu - notacji z nawiasami klamrowymi {}.
1// Prosty obiekt dinozaura utworzony za pomocą literału obiektu
2const velociraptor = {
3 name: "Blue",
4 species: "Velociraptor",
5 age: 4,
6 length: 2.1, // metry
7 weight: 80, // kilogramy
8 maxSpeed: 64, // km/h
9 diet: "carnivore",
10 location: "Sektor B",
11 dangerous: true
12};
13
14console.log(velociraptor.name); // "Blue"
15console.log(velociraptor.species); // "Velociraptor"
16console.log(velociraptor.maxSpeed); // 64Dostęp do właściwości
Możemy uzyskać dostęp do właściwości obiektu na dwa sposoby:
1// Notacja kropkowa
2console.log(velociraptor.diet); // "carnivore"
3
4// Notacja nawiasowa (przydatna, gdy nazwa właściwości jest przechowywana w zmiennej)
5const propertyName = "location";
6console.log(velociraptor[propertyName]); // "Sektor B"
7
8// Notacja nawiasowa jest też przydatna, gdy nazwa właściwości zawiera znaki specjalne lub spacje
9const dinoDetails = {
10 "full name": "Velociraptor antirrhopus",
11 "security-level": "Alpha"
12};
13
14console.log(dinoDetails["full name"]); // "Velociraptor antirrhopus"
15console.log(dinoDetails["security-level"]); // "Alpha"Metody obiektów
Obiekty mogą zawierać również funkcje, które nazywamy metodami:
1const velociraptor = {
2 name: "Blue",
3 species: "Velociraptor",
4 age: 4,
5 hunger: 50, // procent (0-100)
6 health: 100, // procent (0-100)
7
8 // Metoda do karmienia dinozaura
9 feed: function() {
10 if (this.hunger <= 0) {
11 return "Blue nie jest głodna.";
12 }
13
14 this.hunger -= 30;
15 if (this.hunger < 0) this.hunger = 0;
16
17 return "Blue została nakarmiona. Poziom głodu: " + this.hunger + "%";
18 },
19
20 // Krótsza składnia metody (wprowadzona w ES6)
21 makeSound() {
22 return "Blue wydaje ostry, przenikliwy dźwięk!";
23 },
24
25 // Metoda sprawdzająca stan zdrowia
26 checkStatus() {
27 return `Dinozaur: ${this.name} (Gatunek: ${this.species})
28Status zdrowia: ${this.health}%
29Poziom głodu: ${this.hunger}%
30Stan ogólny: ${this.health > 80 ? "Doskonały" : this.health > 50 ? "Dobry" : "Wymaga opieki weterynaryjnej"}`;
31 }
32};
33
34console.log(velociraptor.makeSound()); // "Blue wydaje ostry, przenikliwy dźwięk!"
35console.log(velociraptor.feed()); // "Blue została nakarmiona. Poziom głodu: 20%"
36console.log(velociraptor.checkStatus());Słowo kluczowe this w metodach odnosi się do obiektu, na którym metoda jest wywoływana.
Dynamiczne dodawanie i usuwanie właściwości
Możemy dynamicznie dodawać i usuwać właściwości obiektów JavaScript:
1const triceratops = {
2 name: "Trixie",
3 species: "Triceratops",
4 age: 6
5};
6
7// Dodawanie nowych właściwości
8triceratops.health = 95;
9triceratops["location"] = "Sektor C";
10
11// Dodawanie metody
12triceratops.updateHealth = function(amount) {
13 this.health += amount;
14 if (this.health > 100) this.health = 100;
15 if (this.health < 0) this.health = 0;
16 return `Zdrowie ${this.name} zaktualizowane do ${this.health}%`;
17};
18
19console.log(triceratops.updateHealth(-15)); // "Zdrowie Trixie zaktualizowane do 80%"
20
21// Usuwanie właściwości
22delete triceratops.age;
23console.log(triceratops.age); // undefinedKonstruktory i operator new
Gdy potrzebujemy stworzyć wiele podobnych obiektów, efektywniejszym podejściem jest użycie funkcji konstruktora i operatora new.
1// Funkcja konstruktora dla dinozaurów
2function Dinosaur(name, species, age, diet) {
3 this.name = name;
4 this.species = species;
5 this.age = age;
6 this.diet = diet;
7 this.health = 100;
8 this.hunger = 50;
9
10 // Metoda wspólna dla wszystkich dinozaurów
11 this.feed = function() {
12 this.hunger -= 30;
13 if (this.hunger < 0) this.hunger = 0;
14 return `${this.name} został(a) nakarmiony(a). Poziom głodu: ${this.hunger}%`;
15 };
16}
17
18// Tworzenie nowych instancji dinozaurów
19const blue = new Dinosaur("Blue", "Velociraptor", 4, "carnivore");
20const trixie = new Dinosaur("Trixie", "Triceratops", 6, "herbivore");
21const rex = new Dinosaur("Rex", "Tyrannosaurus", 8, "carnivore");
22
23console.log(blue.species); // "Velociraptor"
24console.log(trixie.diet); // "herbivore"
25console.log(rex.feed()); // "Rex został(a) nakarmiony(a). Poziom głodu: 20%"Funkcja konstruktora tworzy "szablon" dla obiektów, a operator new tworzy nową instancję obiektu zgodnie z tym szablonem.
Zalety konstruktorów:
- Spójność - wszystkie obiekty mają ten sam zestaw właściwości i metod
- Skalowalność - łatwiej tworzyć wiele podobnych obiektów
- Czytelność - kod staje się bardziej przewidywalny i łatwy do utrzymania
Sprawdzanie typu obiektu - operator instanceof
Możemy sprawdzić, czy obiekt został utworzony za pomocą konkretnego konstruktora:
1console.log(blue instanceof Dinosaur); // true
2console.log(velociraptor instanceof Dinosaur); // false (został utworzony jako literał)Klasy (ES6+)
W nowszych wersjach JavaScript (ES6+) wprowadzono klasy, które zapewniają bardziej przyjazną składnię dla programowania obiektowego. Pod maską nadal są to funkcje konstruktora, ale z bardziej czytelną składnią.
1class Dinosaur {
2 constructor(name, species, age, diet) {
3 this.name = name;
4 this.species = species;
5 this.age = age;
6 this.diet = diet;
7 this.health = 100;
8 this.hunger = 50;
9 this.isAsleep = false;
10 }
11
12 // Metody są automatycznie dodawane do prototypu
13 feed() {
14 if (this.isAsleep) {
15 return `${this.name} śpi. Lepiej go/jej nie budzić podczas karmienia.`;
16 }
17
18 this.hunger -= 30;
19 if (this.hunger < 0) this.hunger = 0;
20 return `${this.name} został(a) nakarmiony(a). Poziom głodu: ${this.hunger}%`;
21 }
22
23 sleep() {
24 this.isAsleep = true;
25 return `${this.name} zasypia.`;
26 }
27
28 wakeUp() {
29 this.isAsleep = false;
30 return `${this.name} budzi się.`;
31 }
32
33 getStatus() {
34 return `
35Dinozaur: ${this.name} (Gatunek: ${this.species})
36Wiek: ${this.age} lat
37Dieta: ${this.diet === "carnivore" ? "Mięsożerna" : "Roślinożerna"}
38Status zdrowia: ${this.health}%
39Poziom głodu: ${this.hunger}%
40Stan: ${this.isAsleep ? "Śpi" : "Aktywny"}`;
41 }
42}
43
44// Tworzenie instancji klasy
45const blue = new Dinosaur("Blue", "Velociraptor", 4, "carnivore");
46console.log(blue.getStatus());
47
48console.log(blue.sleep()); // "Blue zasypia."
49console.log(blue.feed()); // "Blue śpi. Lepiej go/jej nie budzić podczas karmienia."
50console.log(blue.wakeUp()); // "Blue budzi się."
51console.log(blue.feed()); // "Blue został(a) nakarmiony(a). Poziom głodu: 20%"Dziedziczenie za pomocą klas
Klasy umożliwiają łatwe implementowanie dziedziczenia:
1// Klasa bazowa
2class Animal {
3 constructor(name, species) {
4 this.name = name;
5 this.species = species;
6 this.alive = true;
7 }
8
9 makeSound() {
10 return "Zwierzę wydaje dźwięk";
11 }
12}
13
14// Klasa pochodna dziedzicząca z Animal
15class Dinosaur extends Animal {
16 constructor(name, species, diet) {
17 // Wywołujemy konstruktor klasy bazowej
18 super(name, species);
19 this.diet = diet;
20 this.health = 100;
21 }
22
23 // Nadpisujemy metodę z klasy bazowej
24 makeSound() {
25 if (this.diet === "carnivore") {
26 return "ROAR!!! Przerażający ryk!";
27 } else {
28 return "Łagodny, niski pomruk.";
29 }
30 }
31
32 // Dodajemy nowe metody
33 eat(food) {
34 if (this.diet === "carnivore" && food.type === "meat") {
35 return `${this.name} zjada ${food.name} z apetytem!`;
36 } else if (this.diet === "herbivore" && food.type === "plant") {
37 return `${this.name} skubie ${food.name} zadowolony.`;
38 } else {
39 return `${this.name} nie jest zainteresowany jedzeniem ${food.name}.`;
40 }
41 }
42}
43
44// Obiekty reprezentujące jedzenie
45const meat = { name: "mięso", type: "meat" };
46const plants = { name: "rośliny", type: "plant" };
47
48// Tworzymy instancje dinozaurów
49const rex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore");
50const spike = new Dinosaur("Spike", "Stegosaurus", "herbivore");
51
52console.log(rex.makeSound()); // "ROAR!!! Przerażający ryk!"
53console.log(spike.makeSound()); // "Łagodny, niski pomruk."
54
55console.log(rex.eat(meat)); // "Rex zjada mięso z apetytem!"
56console.log(rex.eat(plants)); // "Rex nie jest zainteresowany jedzeniem rośliny."
57console.log(spike.eat(plants)); // "Spike skubie rośliny zadowolony."Metody statyczne
Metody statyczne są wywoływane na samej klasie, a nie na jej instancjach:
1class DinosaurDatabase {
2 static dinoCount = 0;
3
4 constructor(name, species) {
5 this.name = name;
6 this.species = species;
7 DinosaurDatabase.dinoCount++;
8 }
9
10 // Metoda instancji - wymaga utworzenia obiektu
11 getInfo() {
12 return `${this.name} (${this.species})`;
13 }
14
15 // Metoda statyczna - wywoływana na klasie, nie na instancji
16 static getTotalDinosaurCount() {
17 return `Całkowita liczba dinozaurów w bazie: ${DinosaurDatabase.dinoCount}`;
18 }
19
20 static compareAge(dino1, dino2) {
21 if (!dino1.age || !dino2.age) return "Brak danych o wieku.";
22
23 if (dino1.age > dino2.age) {
24 return `${dino1.name} jest starszy od ${dino2.name}.`;
25 } else if (dino1.age < dino2.age) {
26 return `${dino1.name} jest młodszy od ${dino2.name}.`;
27 } else {
28 return `${dino1.name} i ${dino2.name} są w tym samym wieku.`;
29 }
30 }
31}
32
33const dino1 = new DinosaurDatabase("Rex", "Tyrannosaurus");
34dino1.age = 8;
35
36const dino2 = new DinosaurDatabase("Blue", "Velociraptor");
37dino2.age = 4;
38
39const dino3 = new DinosaurDatabase("Trixie", "Triceratops");
40dino3.age = 6;
41
42console.log(DinosaurDatabase.getTotalDinosaurCount()); // "Całkowita liczba dinozaurów w bazie: 3"
43console.log(DinosaurDatabase.compareAge(dino1, dino2)); // "Rex jest starszy od Blue."
44console.log(DinosaurDatabase.compareAge(dino2, dino3)); // "Blue jest młodszy od Trixie."Object.create()
Metoda Object.create() pozwala na tworzenie nowych obiektów z określonym prototypem:
1// Obiekt prototypowy dla wszystkich dinozaurów
2const dinoPrototype = {
3 makeSound() {
4 return "Ryk!";
5 },
6 eat() {
7 return `${this.name} je.`;
8 }
9};
10
11// Tworzenie obiektu z prototypem dinoPrototype
12const rex = Object.create(dinoPrototype);
13rex.name = "Rex";
14rex.species = "Tyrannosaurus";
15
16console.log(rex.name); // "Rex"
17console.log(rex.makeSound()); // "Ryk!"
18console.log(rex.eat()); // "Rex je."Factory Functions (Funkcje fabryczne)
Funkcje fabryczne to funkcje, które tworzą i zwracają obiekty bez użycia new:
1// Funkcja fabryczna do tworzenia obiektów dinozaurów
2function createDinosaur(name, species, diet) {
3 return {
4 name, // Skrócona składnia dla name: name w ES6+
5 species,
6 diet,
7 health: 100,
8 hunger: 50,
9
10 feed() {
11 this.hunger -= 30;
12 if (this.hunger < 0) this.hunger = 0;
13 return `${this.name} został(a) nakarmiony(a). Poziom głodu: ${this.hunger}%`;
14 },
15
16 getStatus() {
17 return `${this.name} (${this.species}) - Zdrowie: ${this.health}%, Głód: ${this.hunger}%`;
18 }
19 };
20}
21
22const blue = createDinosaur("Blue", "Velociraptor", "carnivore");
23const trixie = createDinosaur("Trixie", "Triceratops", "herbivore");
24
25console.log(blue.getStatus()); // "Blue (Velociraptor) - Zdrowie: 100%, Głód: 50%"
26console.log(blue.feed()); // "Blue został(a) nakarmiony(a). Poziom głodu: 20%"Praktyczne zastosowanie obiektów w Parku Jurajskim
System zarządzania dinozaurami
1class DinosaurManager {
2 constructor() {
3 this.dinosaurs = [];
4 this.enclosures = [];
5 }
6
7 addDinosaur(dino) {
8 this.dinosaurs.push(dino);
9 console.log(`Dodano nowego dinozaura: ${dino.name} (${dino.species})`);
10 }
11
12 addEnclosure(enclosure) {
13 this.enclosures.push(enclosure);
14 console.log(`Dodano nowy wybieg: ${enclosure.name} (Pojemność: ${enclosure.capacity})`);
15 }
16
17 assignDinosaurToEnclosure(dinoName, enclosureName) {
18 const dino = this.dinosaurs.find(d => d.name === dinoName);
19 const enclosure = this.enclosures.find(e => e.name === enclosureName);
20
21 if (!dino) {
22 return `Błąd: Dinozaur o nazwie ${dinoName} nie znaleziony.`;
23 }
24
25 if (!enclosure) {
26 return `Błąd: Wybieg o nazwie ${enclosureName} nie znaleziony.`;
27 }
28
29 if (enclosure.dinosaurs.length >= enclosure.capacity) {
30 return `Błąd: Wybieg ${enclosureName} osiągnął maksymalną pojemność.`;
31 }
32
33 // Sprawdzenie czy drapieżniki nie są mieszane z roślinożercami
34 if (enclosure.dinosaurs.length > 0) {
35 const existingDiet = enclosure.dinosaurs[0].diet;
36 if (dino.diet === "carnivore" && existingDiet === "herbivore") {
37 return "Błąd: Nie można umieszczać drapieżników z roślinożercami!";
38 }
39 if (dino.diet === "herbivore" && existingDiet === "carnivore") {
40 return "Błąd: Nie można umieszczać roślinożerców z drapieżnikami!";
41 }
42 }
43
44 // Usunięcie dinozaura z poprzedniego wybiegu, jeśli był przypisany
45 this.enclosures.forEach(e => {
46 const index = e.dinosaurs.findIndex(d => d.name === dinoName);
47 if (index !== -1) {
48 e.dinosaurs.splice(index, 1);
49 }
50 });
51
52 // Przypisanie dinozaura do nowego wybiegu
53 enclosure.dinosaurs.push(dino);
54 dino.enclosure = enclosureName;
55
56 return `${dinoName} został(a) przypisany(a) do wybiegu ${enclosureName}.`;
57 }
58
59 getEnclosureReport(enclosureName) {
60 const enclosure = this.enclosures.find(e => e.name === enclosureName);
61
62 if (!enclosure) {
63 return `Błąd: Wybieg o nazwie ${enclosureName} nie znaleziony.`;
64 }
65
66 let report = `=== RAPORT DLA WYBIEGU: ${enclosure.name} ===
67Pojemność: ${enclosure.dinosaurs.length}/${enclosure.capacity}
68Status: ${enclosure.status}
69Dinozaury:\n`;
70
71 if (enclosure.dinosaurs.length === 0) {
72 report += "Brak dinozaurów w tym wybiegu.";
73 } else {
74 enclosure.dinosaurs.forEach(dino => {
75 report += `- ${dino.name} (${dino.species}): Zdrowie: ${dino.health}%, Głód: ${dino.hunger}%\n`;
76 });
77 }
78
79 return report;
80 }
81}
82
83// Klasa dla dinozaurów
84class Dinosaur {
85 constructor(name, species, diet) {
86 this.name = name;
87 this.species = species;
88 this.diet = diet;
89 this.health = 100;
90 this.hunger = 50;
91 this.enclosure = null; // Nazwa wybiegu, do którego przypisany jest dinozaur
92 }
93}
94
95// Klasa dla wybiegów
96class Enclosure {
97 constructor(name, capacity, security) {
98 this.name = name;
99 this.capacity = capacity;
100 this.security = security; // poziom zabezpieczeń
101 this.status = "Operational";
102 this.dinosaurs = []; // Lista dinozaurów w wybiegu
103 }
104}
105
106// Użycie systemu zarządzania
107const parkManager = new DinosaurManager();
108
109// Tworzenie wybiegów
110const carnivoreEnclosure = new Enclosure("Paddock A", 3, "Maximum");
111const herbivoreEnclosure = new Enclosure("Paddock B", 5, "Standard");
112
113parkManager.addEnclosure(carnivoreEnclosure);
114parkManager.addEnclosure(herbivoreEnclosure);
115
116// Tworzenie dinozaurów
117const rex = new Dinosaur("Rex", "Tyrannosaurus", "carnivore");
118const blue = new Dinosaur("Blue", "Velociraptor", "carnivore");
119const trixie = new Dinosaur("Trixie", "Triceratops", "herbivore");
120const spike = new Dinosaur("Spike", "Stegosaurus", "herbivore");
121
122parkManager.addDinosaur(rex);
123parkManager.addDinosaur(blue);
124parkManager.addDinosaur(trixie);
125parkManager.addDinosaur(spike);
126
127// Przypisywanie dinozaurów do wybiegów
128console.log(parkManager.assignDinosaurToEnclosure("Rex", "Paddock A"));
129console.log(parkManager.assignDinosaurToEnclosure("Blue", "Paddock A"));
130console.log(parkManager.assignDinosaurToEnclosure("Trixie", "Paddock B"));
131console.log(parkManager.assignDinosaurToEnclosure("Spike", "Paddock B"));
132
133// Próba przypisania roślinożercy do wybiegu drapieżników
134console.log(parkManager.assignDinosaurToEnclosure("Trixie", "Paddock A"));
135
136// Wyświetlanie raportów
137console.log(parkManager.getEnclosureReport("Paddock A"));
138console.log(parkManager.getEnclosureReport("Paddock B"));Podsumowanie
Obiekty są fundamentalnym elementem języka JavaScript i pozwalają nam modelować złożone struktury danych i zachowania. W Parku Jurajskim używamy ich do reprezentowania wszystkiego - od dinozaurów po system zarządzania całym parkiem.
Mamy kilka sposobów tworzenia obiektów:
- Literały obiektów - najprostszy sposób, idealny dla pojedynczych, unikalnych obiektów
- Funkcje konstruktora - gdy potrzebujemy tworzyć wiele podobnych obiektów
- Klasy (ES6+) - nowoczesna, czytelna składnia do tworzenia szablonów obiektów z dziedziczeniem
- Object.create() - tworzenie obiektów z określonym prototypem
- Funkcje fabryczne - funkcje zwracające nowe obiekty, alternatywa dla konstruktorów
Wybór konkretnej techniki zależy od sytuacji i potrzeb projektu. W złożonych aplikacjach, jak nasz system zarządzania Parkiem Jurajskim, najczęściej używamy kombinacji tych technik.
Kod do tej lekcji: index.js
1// Obiekty - tworzenie - Park Jurajski
2console.log("Laboratorium Obiektów JavaScript");
3console.log("Tworzenie i konstruowanie obiektów\n");
4
5// ===========================================
6// 1. LITERAŁY OBIEKTOWE (najprostszy sposób)
7// ===========================================
8console.log("=== 1. Literały obiektowe ===");
9
10// Podstawowy obiekt
11const dinosaur1 = {
12 name: "T-Rex",
13 species: "Tyrannosaurus Rex",
14 age: 8,
15 weight: 8000,
16 carnivore: true
17};
18
19console.log("Dinozaur 1:");
20console.log(` Imię: ${dinosaur1.name}`);
21console.log(` Gatunek: ${dinosaur1.species}`);
22console.log(` Wiek: ${dinosaur1.age} lat`);
23
24// Obiekt z metodami
25const dinosaur2 = {
26 name: "Blue",
27 species: "Velociraptor",
28 speed: 40,
29
30 // Metoda tradycyjna
31 roar: function() {
32 return `${this.name} ryczy: SHREEK!`;
33 },
34
35 // Metoda skrócona (ES6)
36 run() {
37 return `${this.name} biegnie z prędkością ${this.speed} km/h`;
38 }
39};
40
41console.log("\nDinozaur 2:");
42console.log(` ${dinosaur2.roar()}`);
43console.log(` ${dinosaur2.run()}`);
44
45// ===========================================
46// 2. KONSTRUKTORY FUNKCYJNE
47// ===========================================
48console.log("\n=== 2. Konstruktory funkcyjne ===");
49
50function Dinosaur(name, species, age, weight, carnivore) {
51 this.name = name;
52 this.species = species;
53 this.age = age;
54 this.weight = weight;
55 this.carnivore = carnivore;
56
57 this.getInfo = function() {
58 return `${this.name} (${this.species}) - ${this.age} lat, ${this.weight}kg`;
59 };
60
61 this.roar = function() {
62 return `${this.name} says: ROAARRR!`;
63 };
64}
65
66const trex = new Dinosaur("Rexy", "T-Rex", 8, 8000, true);
67const trike = new Dinosaur("Trike", "Triceratops", 7, 9000, false);
68
69console.log("\nUtworzono przez konstruktor:");
70console.log(` ${trex.getInfo()}`);
71console.log(` ${trex.roar()}`);
72console.log(` ${trike.getInfo()}`);
73
74// ===========================================
75// 3. Object.create()
76// ===========================================
77console.log("\n=== 3. Object.create() ===");
78
79const dinoPrototype = {
80 getInfo() {
81 return `${this.name} (${this.species})`;
82 },
83
84 roar() {
85 return `${this.name}: ROAARRR!`;
86 }
87};
88
89const velociraptor = Object.create(dinoPrototype);
90velociraptor.name = "Charlie";
91velociraptor.species = "Velociraptor";
92velociraptor.age = 5;
93
94console.log("\nUtworzono przez Object.create():");
95console.log(` ${velociraptor.getInfo()}`);
96console.log(` ${velociraptor.roar()}`);
97
98// ===========================================
99// 4. KLASY ES6
100// ===========================================
101console.log("\n=== 4. Klasy ES6 ===");
102
103class DinosaurClass {
104 constructor(name, species, age, weight, carnivore) {
105 this.name = name;
106 this.species = species;
107 this.age = age;
108 this.weight = weight;
109 this.carnivore = carnivore;
110 }
111
112 getInfo() {
113 return `${this.name} (${this.species}) - ${this.age} lat, ${this.weight}kg`;
114 }
115
116 roar() {
117 return `${this.name} says: ROAARRR!`;
118 }
119
120 isHeavy() {
121 return this.weight > 1000;
122 }
123}
124
125const stego = new DinosaurClass("Stego", "Stegosaurus", 6, 5000, false);
126const brachio = new DinosaurClass("Brachio", "Brachiosaurus", 10, 50000, false);
127
128console.log("\nUtworzono przez klasę:");
129console.log(` ${stego.getInfo()}`);
130console.log(` Czy ciężki? ${stego.isHeavy()}`);
131console.log(` ${brachio.getInfo()}`);
132console.log(` Czy ciężki? ${brachio.isHeavy()}`);
133
134// ===========================================
135// 5. FACTORY FUNCTIONS
136// ===========================================
137console.log("\n=== 5. Factory functions ===");
138
139function createDinosaur(name, species, options = {}) {
140 return {
141 name,
142 species,
143 age: options.age || 5,
144 weight: options.weight || 100,
145 carnivore: options.carnivore || false,
146 sector: options.sector || "A",
147
148 getInfo() {
149 return `${this.name} (${this.species}) - Sektor ${this.sector}`;
150 },
151
152 feed() {
153 console.log(`Karmienie ${this.name}`);
154 }
155 };
156}
157
158const dilo = createDinosaur("Dilo", "Dilophosaurus", {
159 age: 4,
160 weight: 400,
161 carnivore: true,
162 sector: "E"
163});
164
165console.log("\nUtworzono przez factory:");
166console.log(` ${dilo.getInfo()}`);
167dilo.feed();
168
169// ===========================================
170// 6. OBIEKTY ZAGNIEŻDŻONE
171// ===========================================
172console.log("\n=== 6. Obiekty zagnieżdżone ===");
173
174const park = {
175 name: "Jurassic Park",
176 location: "Isla Nublar",
177
178 sectors: {
179 A: { name: "Carnivore Zone", capacity: 5, current: 2 },
180 B: { name: "Raptor Pen", capacity: 10, current: 3 },
181 C: { name: "Herbivore Valley", capacity: 20, current: 8 }
182 },
183
184 stats: {
185 totalDinosaurs: 13,
186 totalVisitors: 1500,
187 securityLevel: "HIGH"
188 },
189
190 getReport() {
191 console.log(`\nRaport parku ${this.name}:`);
192 console.log(` Lokalizacja: ${this.location}`);
193 console.log(` Dinozaury: ${this.stats.totalDinosaurs}`);
194 console.log(` Odwiedzający: ${this.stats.totalVisitors}`);
195 console.log(` Bezpieczeństwo: ${this.stats.securityLevel}`);
196 }
197};
198
199park.getReport();
200
201console.log("\nSektory:");
202Object.entries(park.sectors).forEach(([key, sector]) => {
203 console.log(` ${key}: ${sector.name} - ${sector.current}/${sector.capacity}`);
204});
205
206// ===========================================
207// 7. GETTERY I SETTERY
208// ===========================================
209console.log("\n=== 7. Gettery i settery ===");
210
211class ManagedDinosaur {
212 constructor(name, species, health) {
213 this.name = name;
214 this.species = species;
215 this._health = health; // Prywatna właściwość (konwencja)
216 }
217
218 // Getter
219 get health() {
220 return this._health;
221 }
222
223 // Setter z walidacją
224 set health(value) {
225 if (value < 0) value = 0;
226 if (value > 100) value = 100;
227 this._health = value;
228 console.log(` Zdrowie ${this.name} zmienione na ${this._health}%`);
229 }
230
231 get status() {
232 if (this._health >= 80) return "Zdrowy";
233 if (this._health >= 50) return "Średni";
234 return "Krytyczny";
235 }
236}
237
238const managedDino = new ManagedDinosaur("Rex", "T-Rex", 75);
239console.log(`\n${managedDino.name}:`);
240console.log(` Zdrowie: ${managedDino.health}%`);
241console.log(` Status: ${managedDino.status}`);
242
243managedDino.health = 95;
244console.log(` Nowy status: ${managedDino.status}`);
245
246managedDino.health = 150; // Będzie ograniczone do 100
247console.log(` Status po przekroczeniu: ${managedDino.status}`);
248
249// ===========================================
250// 8. STATYCZNE METODY I WŁAŚCIWOŚCI
251// ===========================================
252console.log("\n=== 8. Statyczne metody i właściwości ===");
253
254class DinoSpecies {
255 static species = [
256 "Tyrannosaurus Rex",
257 "Velociraptor",
258 "Triceratops",
259 "Stegosaurus",
260 "Brachiosaurus"
261 ];
262
263 static isCarnivore(species) {
264 const carnivores = ["Tyrannosaurus Rex", "Velociraptor", "Spinosaurus"];
265 return carnivores.includes(species);
266 }
267
268 static getInfo(species) {
269 const info = {
270 "Tyrannosaurus Rex": { weight: 8000, period: "Kredowy" },
271 "Velociraptor": { weight: 80, period: "Kredowy" },
272 "Triceratops": { weight: 9000, period: "Kredowy" }
273 };
274 return info[species] || { weight: "?", period: "?" };
275 }
276
277 static listAll() {
278 console.log("\nWszystkie gatunki:");
279 this.species.forEach((s, i) => {
280 const carnivore = this.isCarnivore(s) ? "mięsożerca" : "roślinożerca";
281 console.log(` ${i + 1}. ${carnivore} ${s}`);
282 });
283 }
284}
285
286DinoSpecies.listAll();
287
288console.log("\nSprawdzanie gatunków:");
289console.log(` T-Rex mięsożerca? ${DinoSpecies.isCarnivore("Tyrannosaurus Rex")}`);
290console.log(` Triceratops mięsożerca? ${DinoSpecies.isCarnivore("Triceratops")}`);
291
292const trexInfo = DinoSpecies.getInfo("Tyrannosaurus Rex");
293console.log(`\nInfo o T-Rex: waga ${trexInfo.weight}kg, okres ${trexInfo.period}`);
294
295// ===========================================
296// 9. DZIEDZICZENIE
297// ===========================================
298console.log("\n=== 9. Dziedziczenie ===");
299
300class Animal {
301 constructor(name, age) {
302 this.name = name;
303 this.age = age;
304 }
305
306 breathe() {
307 return `${this.name} oddycha`;
308 }
309
310 getAge() {
311 return `${this.name} ma ${this.age} lat`;
312 }
313}
314
315class Carnivore extends Animal {
316 constructor(name, age, huntingSkill) {
317 super(name, age);
318 this.huntingSkill = huntingSkill;
319 this.type = "Mięsożerca";
320 }
321
322 hunt() {
323 return `${this.name} poluje (umiejętność: ${this.huntingSkill}/10)`;
324 }
325
326 roar() {
327 return `${this.name} ryczy: ROAARRR!`;
328 }
329}
330
331class Herbivore extends Animal {
332 constructor(name, age, plantPreference) {
333 super(name, age);
334 this.plantPreference = plantPreference;
335 this.type = "Roślinożerca";
336 }
337
338 eat() {
339 return `${this.name} je ${this.plantPreference}`;
340 }
341
342 graze() {
343 return `${this.name} spokojnie się pasie`;
344 }
345}
346
347const rex = new Carnivore("Rexy", 8, 10);
348const trico = new Herbivore("Trico", 7, "paprocie");
349
350console.log("\nMięsożerca:");
351console.log(` ${rex.getAge()}`);
352console.log(` ${rex.breathe()}`);
353console.log(` ${rex.hunt()}`);
354console.log(` ${rex.roar()}`);
355
356console.log("\nRoślinożerca:");
357console.log(` ${trico.getAge()}`);
358console.log(` ${trico.breathe()}`);
359console.log(` ${trico.eat()}`);
360console.log(` ${trico.graze()}`);
361
362// ===========================================
363// 10. PRZYKŁAD KOMPLEKSOWY
364// ===========================================
365console.log("\n=== 10. System zarządzania - przykład kompleksowy ===");
366
367class ParkManagementSystem {
368 constructor(parkName) {
369 this.parkName = parkName;
370 this.dinosaurs = new Map();
371 this.nextId = 1;
372 }
373
374 addDinosaur(name, species, options = {}) {
375 const dino = {
376 id: this.nextId++,
377 name,
378 species,
379 age: options.age || 5,
380 weight: options.weight || 1000,
381 health: options.health || 100,
382 sector: options.sector || "A",
383 carnivore: options.carnivore || false,
384 fed: false,
385 lastCheckup: new Date()
386 };
387
388 this.dinosaurs.set(dino.id, dino);
389 console.log(`Dodano: ${name} (#${dino.id})`);
390 return dino.id;
391 }
392
393 getDinosaur(id) {
394 return this.dinosaurs.get(id);
395 }
396
397 removeDinosaur(id) {
398 const dino = this.dinosaurs.get(id);
399 if (dino) {
400 this.dinosaurs.delete(id);
401 console.log(`Usunięto: ${dino.name} (#${id})`);
402 return true;
403 }
404 return false;
405 }
406
407 feedDinosaur(id) {
408 const dino = this.dinosaurs.get(id);
409 if (dino) {
410 dino.fed = true;
411 console.log(`Nakarmiono: ${dino.name}`);
412 }
413 }
414
415 updateHealth(id, newHealth) {
416 const dino = this.dinosaurs.get(id);
417 if (dino) {
418 dino.health = Math.max(0, Math.min(100, newHealth));
419 console.log(`Zaktualizowano zdrowie ${dino.name}: ${dino.health}%`);
420 }
421 }
422
423 getStats() {
424 const dinos = Array.from(this.dinosaurs.values());
425
426 return {
427 total: dinos.length,
428 carnivores: dinos.filter(d => d.carnivore).length,
429 avgHealth: (dinos.reduce((sum, d) => sum + d.health, 0) / dinos.length).toFixed(1),
430 fed: dinos.filter(d => d.fed).length,
431 bySector: dinos.reduce((acc, d) => {
432 acc[d.sector] = (acc[d.sector] || 0) + 1;
433 return acc;
434 }, {})
435 };
436 }
437
438 displayReport() {
439 console.log(`\n============================================================`);
440 console.log(`RAPORT PARKU: ${this.parkName}`);
441 console.log("=".repeat(60));
442
443 const stats = this.getStats();
444 console.log("\nStatystyki:");
445 console.log(` Łącznie dinozaurów: ${stats.total}`);
446 console.log(` Mięsożercy: ${stats.carnivores}`);
447 console.log(` Średnie zdrowie: ${stats.avgHealth}%`);
448 console.log(` Nakarmione: ${stats.fed}/${stats.total}`);
449
450 console.log("\nPodział na sektory:");
451 Object.entries(stats.bySector).sort().forEach(([sector, count]) => {
452 console.log(` Sektor ${sector}: ${count}`);
453 });
454
455 console.log("\nLista dinozaurów:");
456 Array.from(this.dinosaurs.values())
457 .sort((a, b) => a.id - b.id)
458 .forEach(dino => {
459 const icon = dino.carnivore ? "mięsożerca" : "roślinożerca";
460 const fedStatus = dino.fed ? "√" : "×";
461 console.log(` #${dino.id} ${icon} ${dino.name} (${dino.species})`);
462 console.log(` Sektor ${dino.sector} | Zdrowie: ${dino.health}% | Nakarmiony: ${fedStatus}`);
463 });
464 }
465}
466
467// Demonstracja systemu
468console.log();
469const parkSystem = new ParkManagementSystem("Isla Nublar");
470
471const id1 = parkSystem.addDinosaur("Rexy", "T-Rex", { age: 8, weight: 8000, sector: "A", carnivore: true });
472const id2 = parkSystem.addDinosaur("Blue", "Velociraptor", { age: 5, weight: 80, sector: "B", carnivore: true, health: 100 });
473const id3 = parkSystem.addDinosaur("Charlie", "Velociraptor", { age: 5, weight: 80, sector: "B", carnivore: true, health: 85 });
474const id4 = parkSystem.addDinosaur("Trike", "Triceratops", { age: 7, weight: 9000, sector: "C", health: 70 });
475const id5 = parkSystem.addDinosaur("Stego", "Stegosaurus", { age: 6, weight: 5000, sector: "C" });
476
477console.log();
478parkSystem.feedDinosaur(id1);
479parkSystem.feedDinosaur(id2);
480parkSystem.updateHealth(id4, 85);
481
482parkSystem.displayReport();
483
484console.log("\nGratulacje! Opanowałeś tworzenie obiektów!");Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jakie są dwa sposoby dostępu do właściwości obiektu w JavaScript?
2. Co robi słowo kluczowe 'new' przed wywołaniem funkcji konstruktora?
Zadania praktyczne w grze
- Klikanie w kolejności
Ułóż elementy tworzenia obiektu dinozaura z metodą:
- Edytor kodu
Utwórz obiekt dinosaur z właściwościami name: 'Rexy', species: 'Tyrannosaurus Rex', age: 25 i isCarnivore: true oraz z zagnieżdżonym obiektem stats, który ma właściwość health: 95. Po utworzeniu obiektu dodaj do niego właściwość enclosure o wartości 'Zone A'. Wyświetl w konsoli name w notacji kropkowej i species w notacji nawiasowej.
- Układanie w poziomie
Ułóż elementy tworzenia obiektu literałem:
- Klikanie w kolejności
Ułóż elementy deklaracji obiektu z właściwościami:
- Układanie w poziomie
Ułóż elementy deklaracji obiektu w JavaScript