Vezérlőpult
7. Objektumok · Építőkövek

2. blokk · Építőkövek · 7. fejezet

Objektumok

A tömb sorszámozott listát tárol; az objektum egy dolog nevesített tulajdonságait fogja össze kulcs–érték párokként: egy termék neve, ára, készlete egy helyen. Ez a JavaScript központi adatszerkezete — minden API-válasz, minden req.body, minden konfiguráció objektum. A fejezet végén objektumok tömbjével, a webshop terméklistájával dolgozol.

Élő gyakorló12 feladat automatikus ellenőrzéssel≈ 1,5 óra

Tanulási célok

1Mi az objektum? Objektumliterál

Egy terméket eddig három külön változóval írtunk le (nev, ar, keszlet) — tíz terméknél ez harminc változó, és semmi nem köti össze őket. Az objektum egyetlen értékbe csomagolja az összetartozó adatokat. Kapcsos zárójellel hozzuk létre (ez az objektumliterál), a kulcs: érték párokat vesszővel választjuk el:

const termek = {
  nev: "Vezeték nélküli egér",   // kulcs: nev, érték: szöveg
  ar: 6990,                       // szám
  keszlet: 40,
  akcios: false,                  // logikai
  cimkek: ["periféria", "vezeték nélküli"]   // tömb is lehet érték
};

console.log(termek);
// { nev: 'Vezeték nélküli egér', ar: 6990, keszlet: 40, akcios: false, cimkek: [ 'periféria', 'vezeték nélküli' ] }
const ures = {};                  // üres objektum — később töltjük fel
TömbObjektum
Mit tárolsok hasonló dolgot sorbanegy dolog több tulajdonságát
Elérésindex: t[0]kulcs: o.nev
Sorrendszámítnem lényeges
Példa[6990, 45990, 1990]{ nev: "Egér", ar: 6990 }

A kulcs mindig szöveg (az idézőjel elhagyható, ha érvényes azonosító); az érték bármi lehet — szám, szöveg, logikai, tömb, másik objektum, sőt függvény is.

2Tulajdonságok elérése

Egy tulajdonságot kétféleképpen érhetünk el: pont-jelöléssel (obj.kulcs) vagy szögletes zárójellel (obj["kulcs"]):

const termek = { nev: "Egér", ar: 6990, "szállítási idő": "2 nap" };

console.log(termek.nev);                 // Egér     — pont: a gyakoribb, olvashatóbb
console.log(termek["ar"]);               // 6990     — szögletes zárójel + kulcs szövegként
console.log(termek["szállítási idő"]);   // 2 nap    — szóközös kulcs: CSAK így érhető el

let mezo = "ar";
console.log(termek[mezo]);               // 6990     — DINAMIKUS kulcs: a változó értéke a kulcs
console.log(termek.mezo);                // undefined — ez a "mezo" NEVŰ kulcsot keresné!

console.log(termek.szin);                // undefined — nincs ilyen tulajdonság, de NEM hiba
ℹ️ MELYIKET MIKOR?

Pont, ha a kulcsot kódírás közben ismered (termek.ar). Szögletes zárójel, ha a kulcs egy változóban van (termek[mezo]), vagy szóközt/kötőjelet tartalmaz. A szótár-mintánál (8. szakasz) a dinamikus kulcs lesz a főszereplő.

⚠️ undefined ≠ HIBA — DE A KÖVETKEZŐ LÉPÉS MÁR AZ

Nem létező tulajdonság olvasása csendben undefined-ot ad. Ha viszont ebből próbálsz továbbolvasni (termek.szin.length), azt kapod: Cannot read properties of undefined. Ez a leggyakoribb JavaScript-hibaüzenet — ha látod, valamelyik köztes érték nem az, amire számítottál (elgépelt kulcs?).

3Módosítás, bővítés, törlés, ellenőrzés

Az objektum a létrehozása után is alakítható: meglévő tulajdonság értéke átírható, új tulajdonság egyszerű értékadással jön létre, a delete pedig eltávolít egyet:

const termek = { nev: "Egér", ar: 6990 };

termek.ar = 5990;               // meglévő módosítása
termek.keszlet = 12;            // ÚJ tulajdonság: egyszerűen értéket adunk neki
termek["gyarto"] = "Logi";      // szögletes zárójellel is
console.log(termek);            // { nev: 'Egér', ar: 5990, keszlet: 12, gyarto: 'Logi' }

delete termek.gyarto;           // tulajdonság törlése
console.log(termek);            // { nev: 'Egér', ar: 5990, keszlet: 12 }

Van-e ilyen tulajdonság?

console.log("ar" in termek);                  // true
console.log("gyarto" in termek);              // false — töröltük
console.log(termek.hasOwnProperty("nev"));   // true — ugyanez metódussal

// Miért nem elég a termek.gyarto !== undefined?
const o = { kedvezmeny: undefined };
console.log(o.kedvezmeny !== undefined);    // false — pedig a kulcs LÉTEZIK
console.log("kedvezmeny" in o);              // true  — az in a kulcs létét nézi, nem az értékét

A gyakorlatban az in operátor a kényelmes; a hasOwnProperty abban különbözik, hogy csak az objektum saját tulajdonságait nézi (az örökölteket nem — erről a 12. fejezetben lesz szó).

4Metódusok és a this

Ha egy tulajdonság értéke függvény, azt metódusnak hívjuk — ilyen a push a tömbön vagy a round a Math-on. Saját objektumba is tehetünk metódust, rövid írásmóddal. A metódus törzsében a this arra az objektumra mutat, amelyen a metódust meghívták — így a metódus eléri az objektum többi tulajdonságát:

const kosar = {
  tetelek: 3,
  osszeg: 20970,
  kiir() {                                       // metódus (rövid alak: nem kell "function")
    return `${this.tetelek} tétel, ${this.osszeg} Ft`;   // this = kosar
  },
  hozzaad(ar) {
    this.tetelek++;                              // az objektum saját adatát módosítja
    this.osszeg += ar;
  }
};

kosar.hozzaad(1990);
console.log(kosar.kiir());        // 4 tétel, 22960 Ft
⚠️ ARROW FUNCTION METÓDUSKÉNT: NINCS SAJÁT this

Az arrow functionnek nincs saját this-e — a környezetéből örökli, így kiir: () => this.tetelek nem az objektumra mutatna. Metódust ezért a fenti rövid alakkal (kiir() { … }) vagy function-nal írj, arrow-t pedig callbackekhez használj. A this részleteire a 12. fejezetben, az osztályoknál térünk vissza — most ennyi elég.

5Beágyazott objektumok és objektumok tömbje

Egy tulajdonság értéke lehet másik objektum vagy tömb — így épülnek fel a valódi adatszerkezetek. Az elérés egyszerűen láncolódik:

const rendeles = {
  azonosito: 1042,
  vevo: { nev: "Kiss Anna", cim: { varos: "Szeged", irsz: "6720" } },
  tetelek: ["Egér", "Kábel"],
  fizetve: true
};

console.log(rendeles.vevo.nev);            // Kiss Anna
console.log(rendeles.vevo.cim.varos);      // Szeged — objektum az objektumban
console.log(rendeles.tetelek[1]);          // Kábel  — tömb az objektumban, index
console.log(rendeles.tetelek.length);      // 2
rendeles.vevo.cim.varos = "Pécs";          // mélyen is módosítható

Objektumok tömbje — a webshop terméklistája

A két szerkezet ereje együtt mutatkozik meg: egy tömb, amelyben objektumok vannak. Így tároljuk a termékeket, a rendeléseket, a felhasználókat. A tömböt a 6. fejezet szerint járjuk be, és minden elem egy objektum, amelynek a tulajdonságait olvassuk:

const termekek = [
  { id: 1, nev: "Egér",    ar: 6990,   keszlet: 40 },
  { id: 2, nev: "Monitor", ar: 45990,  keszlet: 0  },
  { id: 3, nev: "Laptop",  ar: 289990, keszlet: 5  }
];

console.log(termekek[1].nev);            // Monitor — 1. elem, nev tulajdonság

// ÖSSZEGZÉS objektumokon: a raktárkészlet értéke
let raktarErtek = 0;
for (const t of termekek) {
  raktarErtek += t.ar * t.keszlet;
}
console.log(raktarErtek);              // 1729550

// KERESÉS objektumokon: termék id szerint (vagy null)
function keresId(lista, id) {
  for (const t of lista) {
    if (t.id === id) return t;         // az egész objektumot adjuk vissza
  }
  return null;                         // "nincs találat" — null, nem undefined
}
console.log(keresId(termekek, 3).nev);   // Laptop
console.log(keresId(termekek, 9));       // null

// ÚJ TÖMB FELÉPÍTÉSE: csak a raktáron lévők
const raktaron = [];
for (const t of termekek) {
  if (t.keszlet > 0) raktaron.push(t);
}
console.log(raktaron.length);          // 2
⚙️ HOL JÖN ELŐ NODE-BAN?

Az API-k JSON-objektumokkal kommunikálnak — a JSON szintaxisa szinte betűre az objektumliterál. Express-ben a beérkező POST kérés törzse, a req.body, egy ilyen objektum, a GET /termekek/:id pedig a fenti keresId — ha null, 404-et küldünk:

app.post('/termekek', (req, res) => {
  const uj = { id: kovetkezoId++, nev: req.body.nev, ar: req.body.ar, keszlet: req.body.keszlet };
  termekek.push(uj);                        // objektum be a tömbbe
  res.status(201).json(uj);                 // objektum vissza JSON-ként
});

6Referencia vs érték — másolás

Ahogy a tömb, az objektum is referencia: a változó nem az objektumot tárolja, hanem rámutat. Értékadással nem másolat készül, hanem két név ugyanarra az objektumra:

const a = { nev: "Egér", ar: 6990 };
const b = a;                     // NEM másolat
b.ar = 1;
console.log(a.ar);               // 1 — a is "változott": ugyanaz az objektum
console.log(a === b);            // true

const c = Object.assign({}, a);  // SEKÉLY MÁSOLAT: új üres objektumba átmásolja a tulajdonságokat
c.ar = 9999;
console.log(a.ar, c.ar);         // 1 9999 — függetlenek
console.log(a === c);            // false — két külön objektum, azonos tartalommal

// Object.assign több forrásból is másol — a későbbi felülírja a korábbit:
const frissitett = Object.assign({}, a, { ar: 5990, akcios: true });
console.log(frissitett);         // { nev: 'Egér', ar: 5990, akcios: true }
ℹ️ const OBJEKTUM — A TARTALOM MÓDOSÍTHATÓ

A const csak azt tiltja, hogy a változó másik objektumra mutasson. A tulajdonságok szabadon írhatók: termek.ar = 5990 rendben van const termek mellett is. Ezért a feladatban, amely „módosítsd az objektumot és add vissza", ugyanazt az objektumot alakítod és return-özöd — ahol viszont „új objektumot" kérünk, ott Object.assign({}, …) vagy egy új {} feltöltése a megoldás.

„Sekély" a másolat, mert csak a legfelső szintet másolja: ha egy tulajdonság értéke maga is objektum vagy tömb, arra az új objektum is ugyanúgy hivatkozik. A 9. fejezetben a spread ({ ...a }) ad ugyanerre rövidebb írásmódot, a mély másolásról pedig a 11. fejezetben lesz szó.

7Bejárás: Object.keys / values / entries, for…in

A tömböt indexszel járjuk be — az objektumnak nincs indexe, de a kulcsait (vagy értékeit) kikérhetjük egy tömbbe, és azon már mehet a ciklus:

const termek = { nev: "Egér", ar: 6990, keszlet: 40 };

console.log(Object.keys(termek));      // [ 'nev', 'ar', 'keszlet' ]      — a kulcsok tömbje
console.log(Object.values(termek));    // [ 'Egér', 6990, 40 ]            — az értékek tömbje
console.log(Object.entries(termek));   // [ [ 'nev', 'Egér' ], [ 'ar', 6990 ], [ 'keszlet', 40 ] ] — párok

console.log(Object.keys(termek).length);   // 3 — hány tulajdonsága van

for (const kulcs of Object.keys(termek)) {
  console.log(kulcs + ": " + termek[kulcs]);      // dinamikus kulcs: itt kell a szögletes zárójel!
}
// nev: Egér  /  ar: 6990  /  keszlet: 40

A for…in ciklus közvetlenül a kulcsokon megy végig — ugyanaz, mint a for…of az Object.keys-en, csak rövidebb. Ne keverd a kettőt: for…of → tömb elemei, for…in → objektum kulcsai:

for (const kulcs in termek) {
  console.log(kulcs, "=", termek[kulcs]);
}

// Másolás kézzel — így működik belül az Object.assign:
function masol(o) {
  const uj = {};
  for (const k in o) {
    uj[k] = o[k];                // dinamikus kulccsal írunk az új objektumba
  }
  return uj;
}
EszközMit ad / mit jár beTipikus használat
Object.keys(o)kulcsok tömbjehány mező van; kulcs szerinti bejárás
Object.values(o)értékek tömbjeértékek összegzése, pl. egy számláló összesítése
Object.entries(o)[kulcs, érték] párok tömbjekulcs és érték együtt kell (10. fejezettől map-pel)
for (const k in o)kulcsok, egyenkéntátmásolás, átalakítás új objektumba

8Az objektum mint szótár

Az objektumot nem csak „egy dolog leírására" használjuk. Ha a kulcsok futás közben keletkeznek — például kategórianevek, szavak, felhasználónevek —, az objektum egy szótár (kulcs → érték táblázat). A klasszikus feladat a számlálás kulcsonként: hány termék van kategóriánként?

const termekek = [
  { nev: "Egér",        kategoria: "periferia" },
  { nev: "Monitor",     kategoria: "kijelzo" },
  { nev: "Billentyűzet", kategoria: "periferia" },
  { nev: "Webkamera",   kategoria: "periferia" }
];

const szamlalo = {};                          // üres szótárral indulunk
for (const t of termekek) {
  const k = t.kategoria;                      // a kulcs az adatból jön → szögletes zárójel
  if (k in szamlalo) {
    szamlalo[k]++;                            // már láttuk: növeljük
  } else {
    szamlalo[k] = 1;                          // első előfordulás: új kulcs, 1-ről indul
  }
}
console.log(szamlalo);                        // { periferia: 3, kijelzo: 1 }

for (const k in szamlalo) {                     // az eredmény kiolvasása
  console.log(`${k}: ${szamlalo[k]} db`);
}
✅ A SZÓTÁR-MINTA LÉNYEGE

1) üres {}; 2) a ciklusban a kulcsot az adatból veszed, és szögletes zárójellel írsz (szamlalo[k], nem szamlalo.k!); 3) „ha már van, frissítsd; ha nincs, hozd létre". Ugyanígy készül ár-összeg kategóriánként, csoportosítás, gyors keresőtábla id szerint. A 11. fejezet Map-je ugyanezt tudja, kicsit másképp.

9Élő kód — próbáld ki!

Kísérletezz az objektumokkal: adj hozzá és törölj tulajdonságot, próbáld ki a dinamikus kulcsot, nézd meg, mi történik két változóval, amely ugyanarra az objektumra mutat, és építs szótárat. A kimenet úgy jelenik meg, ahogy Node-ban a console.log mutatná.

JavaScript-gyakorló

Válassz mintát vagy írj sajátot — majd Futtatás (Ctrl+Enter) ↓

A kimenet itt jelenik meg…

10Feladatok

Egy megadott nevű függvényt írsz; az ellenőrző meghívja, és a visszaadott értéket hasonlítja a várthoz. Objektumnál ez azt jelenti: pontosan a kért kulcsok legyenek benne (se több, se kevesebb), a megfelelő értékekkel — a kulcsok sorrendje nem számít. A paraméterek termékobjektumok ({ nev, ar, keszlet }) vagy ilyenek tömbje. Figyeld a leírást: hol kell új objektumot visszaadni, és hol a kapottat módosítani. Csak az eddig tanultakat használd (ciklusok, tömb-alapok, Object.keys/values/entries, Object.assign, for…in).

Gyakorló feladatok

⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás — a haladásod ebben a böngészőben megmarad.

Kész: 0 / 0
✅ OBJEKTUMOK TÖMBJÉNÉL

Ugyanaz a négy minta, mint a 6. fejezetben (összegzés, számlálás, legjobb-eddig, új tömb felépítése) — csak a ciklusváltozó egy objektum, és a t.ar, t.keszlet tulajdonságával számolsz. Ha a „legdrágábbat" kérik, az egész objektumot jegyezd meg, ne csak az árát.

11Összegzés

  1. Az objektum kulcs–érték párok gyűjteménye: { nev: "Egér", ar: 6990 }. Egy dolog tulajdonságait fogja össze; az érték bármi lehet (tömb, objektum, függvény is).
  2. Elérés: o.kulcs (ismert kulcs) vagy o["kulcs"] / o[valtozo] (dinamikus vagy szóközös kulcs). Nem létező tulajdonság → undefined.
  3. Módosítás értékadással, új tulajdonság ugyanúgy, törlés delete o.kulcs. Létezés: "kulcs" in o vagy o.hasOwnProperty("kulcs").
  4. Metódus = függvény értékű tulajdonság (kiir() { … }); benne a this az objektum. Arrow functionnek nincs saját this-e — metódusnak ne használd.
  5. Beágyazás láncolt eléréssel (rendeles.vevo.cim.varos); objektumok tömbje a webshop adatformátuma — a 6. fejezet mintái objektum-tulajdonságokkal (t.ar * t.keszlet).
  6. Az objektum referencia: b = a ugyanarra mutat; Object.assign({}, a) sekély másolat, Object.assign({}, a, b) összefésül (b felülír). A const objektum tartalma módosítható.
  7. Bejárás: Object.keys / values / entries tömböt ad; for (const k in o) a kulcsokon megy. Szótár-minta: üres {}, kulcs az adatból, o[k]-val írsz — „ha van, frissítsd, ha nincs, hozd létre".
➡️ KÖVETKEZŐ LÉPÉS

Az adatszerkezetek megvannak: függvény, tömb, objektum. A következő fejezetben a szövegkezelést vesszük sorra — a string-metódusokat (toUpperCase, includes, slice, split, trim…), amelyekkel a felhasználótól érkező adatokat tisztítjuk és ellenőrizzük. Sok metódus neve ismerős lesz a tömbökből — nem véletlenül.