Kurs JavaScript i TypeScript · Moduł 5: Zaawansowany JavaScript

Obiekty i tablice w JavaScript

6 min czytania
W tej lekcji5

W Parku Jurajskim przechowujemy ogromne ilości danych o dinozaurach - ich imiona, gatunki, wiek, status zdrowia i wiele więcej. Wyobraź sobie że każdą informację trzymasz w osobnej zmiennej: blueName, blueAge, blueSpecies, a potem to samo dla Charliego i Delty. Po tygodniu laboratorium tonie w probówkach bez etykiet. Aby efektywnie zarządzać tymi danymi, potrzebujemy dwóch fundamentalnych struktur danych JavaScript: obiektów i tablic.

Czego się nauczysz

  • składać dane dinozaura w obiekt, czyli kartę DNA
  • odczytywać, zmieniać i usuwać właściwości
  • dopisywać do karty metody, czyli zachowania
  • budować i zagnieżdżać tablice
  • rozpoznawać wzorce: od literału do klasy

Obiekty - karty DNA dinozaurów

Obiekt w JavaScript to kolekcja par klucz-wartość, która pozwala przechowywać powiązane ze sobą dane w jednym miejscu. Pomyśl o obiekcie jak o karcie informacyjnej dinozaura - zawiera wszystkie istotne dane w uporządkowany sposób.

Tworzenie obiektów

Najprostszym sposobem tworzenia obiektu jest użycie nawiasów klamrowych {}, czyli literału obiektu. W środku wpisujesz pary: klucz, dwukropek i wartość, oddzielone przecinkami:

1// Karta informacyjna Velociraptora
2const raptor = {
3  name: "Blue",
4  species: "Velociraptor",
5  age: 4,
6  isAlpha: true,
7  dangerLevel: 8
8};
9
10console.log(raptor); // Wyświetli cały obiekt

Cała karta Blue to teraz jedna wartość w jednej stałej. Zapis new Object() też istnieje, ale literał jest krótszy i to on jest standardem. Nie myl nawiasów: klamry {} tworzą obiekt, a kwadratowe [] tablicę.

Dostęp do właściwości obiektu

Istnieją dwa sposoby dostępu do właściwości obiektu: notacja kropkowa oraz notacja nawiasowa, w której nazwę klucza podajesz jako tekst:

1// 1. Notacja kropkowa (dot notation) - najczęściej używana
2console.log(raptor.name);      // "Blue"
3console.log(raptor.age);       // 4
4
5// 2. Notacja nawiasowa (bracket notation) - przydatna dla dynamicznych kluczy
6console.log(raptor["species"]); // "Velociraptor"
7
8const property = "dangerLevel";
9console.log(raptor[property]);  // 8 - użyteczne gdy klucz jest w zmiennej

Obie drogi prowadzą do tej samej wartości. Kropkę polecam na co dzień a nawiasy zostaw na klucze zapisane w zmiennej. Zapis raptor->name znany z innych języków jest tu błędem składni, a odczyt nieistniejącego klucza zwraca po prostu undefined.

Modyfikowanie i dodawanie właściwości

Karta dinozaura nie jest wyryta w kamieniu: wiek rośnie, raptor zmienia wybieg, a niektóre wpisy trzeba wykreślić. Wystarczy przypisanie albo operator delete:

1// Modyfikowanie istniejącej właściwości
2raptor.age = 5;
3
4// Dodawanie nowej właściwości
5raptor.habitat = "Wybieg A3";
6
7// Usuwanie właściwości
8delete raptor.habitat;

Przypisanie do istniejącego klucza nadpisuje wartość, do nowego dopisuje właściwość, a delete usuwa ją całkowicie. Co się nie zmieniło? raptor nadal wskazuje ten sam obiekt - const zabrania tylko ponownego przypisania stałej, a nie zmian w środku.

Metody obiektu

Obiekt może zawierać funkcje jako wartości - nazywamy je metodami. To zachowania dinozaura zapisane tuż obok jego danych:

1const raptor = {
2  name: "Blue",
3  age: 4,
4  isAlpha: true,
5  skills: ["hunt", "communicate", "lead"],
6
7  // Metoda - funkcja wewnątrz obiektu
8  attack() {
9    return this.name + " atakuje!";
10  },
11
12  // Inna metoda z użyciem this
13  introduce() {
14    return "Jestem " + this.name + ", wiek: " + this.age + ".";
15  }
16};
17
18console.log(raptor.attack());     // "Blue atakuje!"
19console.log(raptor.introduce());  // "Jestem Blue, wiek: 4."

Wewnątrz metody this wskazuje obiekt, na którym ją wywołano, dlatego raptor.attack() zna imię Blue bez żadnego argumentu. Właściwość skills pokazuje przy okazji, że wartością może być cała tablica.

Trzy sposoby zapisu metody

Metodę możesz zapisać na trzy sposoby i wszystkie są poprawnym JavaScriptem. Porównajmy je na jednej karcie:

1const raptor = {
2  name: "Blue",
3  // 1. Skrócony zapis metody (ES6)
4  hunt() { return this.name + " poluje"; },
5  // 2. Właściwość z wyrażeniem funkcyjnym
6  communicate: function () { return this.name + " się komunikuje"; },
7  // 3. Właściwość z funkcją strzałkową
8  roar: () => "Wrrr!"
9};
10
11console.log(raptor.hunt());        // "Blue poluje"
12console.log(raptor.communicate()); // "Blue się komunikuje"
13console.log(raptor.roar());        // "Wrrr!"

Dwa pierwsze zapisy działają identycznie. Funkcja strzałkowa nie ma własnego this, więc this.name w jej wnętrzu nie wskaże raptora. Polecam skrócony zapis: jest najkrótszy, a this działa w nim przewidywalnie.

Metody statyczne Object

JavaScript udostępnia kilka przydatnych metod do pracy z obiektami. Wywołujesz je na globalnym Object, a kartę podajesz jako argument:

1const dino = { name: "Rex", species: "T-Rex", age: 12 };
2
3// Object.keys() - tablica kluczy
4console.log(Object.keys(dino));   // ["name", "species", "age"]
5
6// Object.values() - tablica wartości
7console.log(Object.values(dino)); // ["Rex", "T-Rex", 12]
8
9// Object.entries() - tablica par [klucz, wartość]
10console.log(Object.entries(dino));
11// [["name", "Rex"], ["species", "T-Rex"], ["age", 12]]

Każda z nich zwraca nową tablicę, a obiekt dino zostaje nietknięty. Klucze przydadzą się do sprawdzenia pól karty, a pary z Object.entries() do pętli po kluczach i wartościach naraz.

Tablice - listy dinozaurów

Tablica to uporządkowana lista elementów, idealna do przechowywania kolekcji danych tego samego typu.

Tworzenie tablic

Tablicę tworzysz nawiasami kwadratowymi [], oddzielając elementy przecinkami. Każdy element ma numer pozycji, czyli indeks, liczony od zera:

1// Tablica nazw Velociraptorów
2const raptors = ["Blue", "Charlie", "Delta", "Echo"];
3
4// Tablica obiektów
5const dinosaurs = [
6  { name: "Blue", species: "Velociraptor", age: 4 },
7  { name: "Rex", species: "T-Rex", age: 12 },
8  { name: "Bronto", species: "Brachiosaurus", age: 8 }
9];
10
11console.log(raptors[0]);        // "Blue" - pierwszy element (indeks 0)
12console.log(raptors.length);    // 4 - liczba elementów
13console.log(dinosaurs[1].name); // "Rex" - dostęp do obiektu w tablicy

Ostatni z czterech raptorów ma więc indeks 3, czyli length - 1. Odczyt spoza zakresu, na przykład raptors[10], zwraca undefined zamiast błędu. Do pól obiektu w tablicy sięgasz, łącząc indeks z kropką.

Złożone struktury danych

Obiekty i tablice można zagnieżdżać, tworząc złożone struktury danych - mapa parku zawiera sektory, a każdy sektor listę mieszkańców:

1const park = {
2  name: "Jurassic Park",
3  sectors: [
4    {
5      id: "A",
6      name: "Strefa drapieżników",
7      dinosaurs: ["T-Rex", "Velociraptor"]
8    },
9    {
10      id: "B",
11      name: "Strefa roślinożerców",
12      dinosaurs: ["Brachiosaurus", "Triceratops"]
13    }
14  ]
15};
16
17console.log(park.sectors[0].dinosaurs[1]); // "Velociraptor"

Ścieżkę park.sectors[0].dinosaurs[1] czytasz od lewej: park, pierwszy sektor, jego lista, drugi element. Każdy krok to zwykła kropka albo zwykły indeks.

Od karty do fabryki - wzorce obiektów

Gdy przybywa raptorów, przepisywanie karty dla każdego szybko męczy. Wzorce rosną schodkami: zwykły obiekt, obiekt z metodami, funkcja fabrykująca, funkcja konstruująca i klasa. Funkcja fabrykująca przy każdym wywołaniu zwraca nowy obiekt:

1function createRaptor(name, age) {
2  return {
3    name,
4    age,
5    attack() {
6      return this.name + " atakuje!";
7    }
8  };
9}
10
11const charlie = createRaptor("Charlie", 3);
12console.log(charlie.attack()); // "Charlie atakuje!"

Zapis name, to skrót od name: name. Wyżej stoją funkcja konstruująca wywoływana z new, której metody trafiają do wspólnego prototypu, oraz klasa - nowocześniejszy zapis tego samego mechanizmu. Klasy znasz z lokacji o składni ES6, a tutaj wrócą we wzorcu Builder.

Tablica czy obiekt?

Wybór struktury zaczyna się od analizy danych: szukasz po kolejności czy po nazwie? Stado przeglądane po kolei to tablica, opis jednego osobnika z nazwanymi cechami to obiekt. Potem implementujesz i testujesz, a optymalizację zostawiasz na koniec.

W laboratorium poniżej czeka karta Blue i pusta mapa parku - uzupełnij sektory zgodnie z komentarzami TODO. W kolejnej lekcji zaczniesz zarządzać stadem metodami tablic, takimi jak push() i splice().

Pamiętaj: obiekt to karta DNA jednego dinozaura, a tablica to lista całego stada.

Kod do tej lekcji: index.js
1// Obiekty i tablice w Parku Jurajskim
2
3// === OBIEKTY ===
4// Stworz obiekt raptor z wlasciwosciami: name, species, age, isAlpha, skills (tablica)
5const raptor = {
6  name: "Blue",
7  age: 4,
8  isAlpha: true,
9  skills: ["hunt", "communicate", "lead"],
10
11  // Dodaj metode attack() ktora zwraca: this.name + " atakuje!"
12  attack() {
13    return this.name + " atakuje!";
14  }
15};
16
17console.log("=== Obiekt raptor ===");
18console.log("Imie:", raptor.name);
19console.log("Wiek:", raptor.age);
20console.log("Atak:", raptor.attack());
21console.log("Pierwsza umiejetnosc:", raptor.skills[0]);
22
23// Metody Object
24console.log("\n=== Metody Object ===");
25console.log("Klucze:", Object.keys(raptor));
26console.log("Wartosci:", Object.values(raptor));
27
28// === TABLICE ===
29const raptors = ["Blue", "Charlie", "Delta", "Echo"];
30console.log("\n=== Tablica raptors ===");
31console.log("Stado:", raptors);
32console.log("Pierwszy:", raptors[0]);
33console.log("Dlugosc:", raptors.length);
34
35// === ZLOZONE STRUKTURY ===
36// TODO: Stworz obiekt park z wlasciwoscia sectors (tablica obiektow)
37// Kazdy sektor powinien miec: id, name, dinosaurs (tablica)
38const park = {
39  name: "Jurassic Park",
40  sectors: [
41    // TODO: Dodaj sektory
42  ]
43};
44
45console.log("\n=== Park ===");
46console.log(park);

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Która z poniższych jest poprawną składnią tworzenia obiektu w JavaScript?

  2. 2. Które z poniższych sposobów dostępu do właściwości obiektu są poprawne?

To 2 z 5 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Edytor kodu

    Stwórz: const raptor = { name: 'Blue', age: 4, isAlpha: true, skills: ['hunt', 'communicate', 'lead'], attack() { return this.name + ' atakuje!' } }. Wywołaj raptor.attack() i raptor.skills[0].

Przydatne artykuły