Vezérlőpult
9. Modern szintaxis (ES6+) · Modern JS

3. blokk · Modern JS · 9. fejezet

Modern szintaxis (ES6+)

A JavaScript 2015-ben (ES6) és azóta minden évben kapott olyan rövidítéseket, amelyek nem új képességet adnak, hanem a mindennapi műveleteket teszik tömörebbé: értékek kiszedése tömbből és objektumból, másolás, összefésülés, biztonságos mélyre nyúlás. Egy mai Express-kód minden sorában ott van valamelyik — nélkülük olvasni sem tudnád. Ebben a fejezetben mindet megtanulod, és rögtön látod, hol jön elő a szerveren.

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

Tanulási célok

1Miért kell ez?

Nézd meg ezt a részletet egy tipikus Express-útvonalból — még nem kell értened a keretrendszert, csak a szintaxist figyeld:

app.post("/termekek/:id", (req, res) => {
  const { id } = req.params;                       // ← destrukturálás
  const { nev, ar = 0 } = req.body;                 // ← destrukturálás alapértékkel
  const regi = termekek.find(t => t.id === id);
  const uj = { ...regi, nev, ar };                // ← spread + rövidített tulajdonságnév
  const varos = uj.szallitas?.cim?.varos ?? "—";  // ← optional chaining + nullish coalescing
  res.json(uj);
});

Öt sorban öt „modern" elem. Ezek mind rövidítések: mindegyik leírható a régi módon is, csak hosszabban. A fejezet végén ezt a kódot folyékonyan olvasod. Egy mondat ismétlés a 2. fejezetből: változót const-tal (ha nem változik) vagy let-tel deklarálunk — a var-t a modern kódban nem használjuk.

2Destrukturálás tömbből

A destrukturálás egy tömb elemeit egyetlen lépésben külön változókba teszi. Bal oldalon a változók „mintája" áll szögletes zárójelben, jobb oldalon a tömb — pozíció szerint párosít:

Régi mód
const pont = [47.5, 19.0];
const szelesseg = pont[0];
const hosszusag = pont[1];
Destrukturálással
const pont = [47.5, 19.0];
const [szelesseg, hosszusag] = pont;
// szelesseg = 47.5, hosszusag = 19.0

Elemeket ki lehet hagyni (üres hely vesszővel), alapértéket lehet adni a hiányzó elemeknek, és a klasszikus „csere" is egy sor lesz:

const [, masodik] = ["első", "második", "harmadik"];
console.log(masodik);            // "második" — az elsőt kihagytuk

const [a, b, c = 0] = [1, 2];
console.log(a, b, c);            // 1 2 0 — c-nek nincs párja, az alapértéket kapja

let x = 1, y = 2;
[x, y] = [y, x];                 // csere segédváltozó nélkül
console.log(x, y);               // 2 1

const [nev, kiterjesztes] = "kep.png".split(".");   // split eredményét rögtön szétszedjük
console.log(nev, kiterjesztes);  // kep png

3Destrukturálás objektumból

Objektumnál a minta kapcsos zárójelben áll, és kulcsnév szerint párosít (a sorrend nem számít). Ez a leggyakoribb forma — egy objektum mezőit egy lépésben változókká tesszük:

Régi mód
const termek = { nev: "Egér", ar: 6990, keszlet: 3 };
const nev = termek.nev;
const ar = termek.ar;
Destrukturálással
const termek = { nev: "Egér", ar: 6990, keszlet: 3 };
const { nev, ar } = termek;
// nev = "Egér", ar = 6990 (keszlet nem kell → nem vesszük ki)

Három bővítés: átnevezés (kulcs: ujNev), alapérték hiányzó mezőnek (kulcs = ertek), és beágyazott objektum kibontása:

const termek = { nev: "Egér", ar: 6990, meret: { szel: 6, hossz: 11 } };

const { ar: egysegar } = termek;             // az ar mezőt egysegar néven vesszük ki
console.log(egysegar);                       // 6990  (ar nevű változó NEM jön létre)

const { akcios = false, keszlet = 0 } = termek;  // nincsenek ilyen mezők → alapértékek
console.log(akcios, keszlet);                // false 0

const { meret: { szel, hossz } } = termek;   // beágyazott: a meret belsejéből
console.log(szel, hossz);                    // 6 11  (meret nevű változó nem jön létre)

Függvényparaméterben

A destrukturálás a paraméterlistában is működik: ha a függvény egy objektumot kap, a fejlécében rögtön kibonthatod, amire szükséged van — így a törzsben nem kell termek.nev-et írni:

function leiras({ nev, ar, keszlet = 0 }) {
  return `${nev}: ${ar} Ft (${keszlet} db)`;
}
console.log(leiras({ nev: "Egér", ar: 6990 }));   // Egér: 6990 Ft (0 db)

// arrow függvénnyel is:
const nevKiir = ({ nev }) => console.log(nev);
nevKiir({ nev: "Monitor", ar: 45990 });         // Monitor
⚙️ HOL JÖN ELŐ NODE-BAN?

Express-ben minden útvonal-kezelő első sorai destrukturálnak: const { id } = req.params; az URL-ből (/termekek/:id), const { nev, ar = 0 } = req.body; a beküldött JSON-ból, const { oldal = 1, limit = 20 } = req.query; a ?oldal=2 lekérdezésből — alapértékkel, hogy hiányzó paraméternél is működjön. Modulok betöltésénél is ez van: const { readFile } = require("fs");.

4Spread: másolás és összefésülés

A spread operátor (...) egy tömböt vagy objektumot „kiterít": az elemeit/mezőit egyenként odaírja, ahol áll. Tömbnél ez másolást, összefűzést és „tömb → külön argumentumok" átalakítást ad:

const a = [1, 2, 3];
const b = [4, 5];

const masolat = [...a];              // [1, 2, 3] — ÚJ tömb, nem ugyanaz a hivatkozás
const egyben = [...a, ...b];         // [1, 2, 3, 4, 5]
const bovitett = [0, ...a, 99];     // [0, 1, 2, 3, 99]

console.log(Math.max(...a));         // 3 — Math.max(1, 2, 3): külön argumentumok kell neki
console.log(Math.max(a));            // NaN — tömböt nem tud kezelni

Objektumnál ugyanez a jel a mezőket másolja át. A sorrend számít: ha ugyanaz a kulcs kétszer szerepel, a később írt nyer — ezért a spread után írt mező felülír. Ez a „módosított másolat" minta, a modern JS egyik legfontosabb fogása:

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

const masolat = { ...termek };                    // új objektum, ugyanazok a mezők
const akcios  = { ...termek, ar: 4990 };          // másolat, de az ar felülírva
const cimkezett = { ...termek, kategoria: "periféria" };   // másolat + új mező

console.log(akcios.ar);      // 4990
console.log(termek.ar);      // 6990 — az EREDETI nem változott!

// két objektum összefésülése: alapértékek + a felhasználó választása
const alap = { szin: "kék", meret: "M", db: 1 };
const valasztas = { meret: "L" };
console.log({ ...alap, ...valasztas });   // { szin: "kék", meret: "L", db: 1 }
console.log({ ...valasztas, ...alap });   // { meret: "M", szin: "kék", db: 1 } — fordítva az alap nyer!
⚠️ CSAK A FELSŐ SZINTET MÁSOLJA

A spread sekély másolat: ha az objektumban egy másik objektum vagy tömb van (pl. meret: { szel, hossz }), annak csak a hivatkozása másolódik — a belső objektum közös marad. Egyszerű, „lapos" adatoknál ez nem gond; beágyazottnál a belső szintet is spread-elni kell: { ...termek, meret: { ...termek.meret, szel: 7 } }.

5Rest: a „többi"

Ugyanaz a három pont a bal oldalon (paraméterlistában vagy destrukturáló mintában) az ellenkezőjét csinálja: összegyűjti a „többit" egy tömbbe. Rest paraméterrel a függvény bármennyi argumentumot fogad:

function osszeg(...szamok) {          // szamok: közönséges tömb az összes argumentummal
  let s = 0;
  for (const x of szamok) {
    s += x;
  }
  return s;
}
console.log(osszeg(1, 2, 3, 4));   // 10
console.log(osszeg());             // 0 — üres tömb

function naplo(szint, ...uzenetek) { // az első kötelező, a többi a rest-be megy
  console.log(`[${szint}]`, uzenetek.join(" "));
}
naplo("INFO", "szerver", "elindult");   // [INFO] szerver elindult

Destrukturálásban a rest az első néhány elem után a maradékot gyűjti tömbbe (tömbnél), illetve a ki nem vett mezőket objektumba (objektumnál):

const [elso, ...tobbi] = [10, 20, 30, 40];
console.log(elso, tobbi);        // 10 [ 20, 30, 40 ]

const { jelszo, ...nyilvanos } = { nev: "anna", email: "a@b.hu", jelszo: "titok" };
console.log(nyilvanos);          // { nev: "anna", email: "a@b.hu" } — a jelszó nélkül
ℹ️ SPREAD VAGY REST? — A HELYE DÖNTI EL

Ugyanaz a ... jel. Ha jobb oldalon / hívásban áll ([...a], f(...t)), kiterít → spread. Ha bal oldalon / paraméterlistában áll (const [x, ...r] =, function f(...args)), összegyűjt → rest. A rest csak az utolsó helyen állhat.

6Objektum-rövidítések

Három apró kényelmi szintaxis objektumliterálokhoz. A leggyakoribb a rövidített tulajdonságnév: ha a kulcs neve ugyanaz, mint a változóé, elég egyszer leírni:

const nev = "Egér";
const ar = 6990;

const regi = { nev: nev, ar: ar };   // régi mód
const uj = { nev, ar };              // ugyanaz rövidítve → { nev: "Egér", ar: 6990 }

function termekLetrehoz(nev, ar, keszlet = 0) {
  return { nev, ar, keszlet };       // paraméterekből objektum egy sorban
}

A számított kulcs ([kifejezés]: érték) akkor kell, ha a kulcs neve egy változóban van. A metódus-rövidítés pedig a nev: function() {} helyett nev() {}:

const mezo = "keszlet";
const o = { [mezo]: 12 };            // { keszlet: 12 } — a kulcs a mezo változó értéke
const o2 = { ["ar_" + "eur"]: 18 };   // { ar_eur: 18 } — bármilyen kifejezés lehet

const kosar = {
  tetelek: [],
  hozzaad(termek) {                  // metódus-rövidítés (= hozzaad: function(termek) {…})
    this.tetelek.push(termek);
  },
  darab() {
    return this.tetelek.length;
  }
};
kosar.hozzaad("Egér");
console.log(kosar.darab());          // 1

7Optional chaining ?.

Ha egy láncban valahol undefined vagy null áll, a további pont hibát dob — ez a JavaScript leggyakoribb futási hibája („Cannot read properties of undefined"). Az optional chaining (?.) helyett hiba nélkül undefined-ot ad, és a lánc többi része már ki sem értékelődik:

const rendeles = { id: 1, vevo: { nev: "Anna" } };   // nincs cim!

// console.log(rendeles.vevo.cim.varos);   // ✗ HIBA: cim undefined, .varos-t nem olvashatjuk
console.log(rendeles.vevo?.cim?.varos);    // undefined — csendben
console.log(rendeles.vevo?.nev);           // "Anna" — ahol van érték, ott sima pontként működik

const semmi = null;
console.log(semmi?.barmi?.melyen);         // undefined — null-nál is

Működik tömbindexre (t?.[0]) és függvényhívásra is (fn?.() — csak akkor hív, ha a függvény létezik):

const beallitas = { };
beallitas.onKesz?.();                      // nincs ilyen függvény → nem történik semmi, hiba sem

const tetelek = rendeles.tetelek;          // undefined
console.log(tetelek?.[0]?.nev);            // undefined
✅ CSAK OTT, AHOL TÉNYLEG HIÁNYOZHAT

Ne szórd tele a kódot ?.-lal! Ahol egy mező biztosan létezik, írj sima pontot — ha ott mégis hiba van, azt látni akarod. A ?. oda való, ahol az adat valóban opcionális: a vevő megadhatta a címét, de nem kötelező.

8Nullish coalescing ??

Az a ?? b értéke a, ha az nem null és nem undefined; különben b. „Alapérték, ha hiányzik." Ismerős a 3. fejezetből az a || b, ami hasonlót csinál — de az minden hamis értéket lecserél, a 0-t és az üres szöveget is. Ez a különbség gyakran okoz hibát:

a értékea || "alap"a ?? "alap"
undefined"alap""alap"
null"alap""alap"
0"alap" ⚠️0
"""alap" ⚠️""
false"alap" ⚠️false
"Egér", 42az értékaz érték
const keszlet = 0;                  // tényleg nulla darab van
console.log(keszlet || 10);         // 10 — ROSSZ: a 0 hamis, ezért „hiányzónak" nézte
console.log(keszlet ?? 10);         // 0  — JÓ: a 0 érvényes érték

const megjegyzes = "";              // a vevő szándékosan üresen hagyta
console.log(megjegyzes || "—");    // "—"
console.log(megjegyzes ?? "—");    // ""

// a tipikus páros: ?. a mélyre nyúláshoz, ?? az alapértékhez
const rendeles = { vevo: { nev: "Anna" } };
const varos = rendeles.vevo?.cim?.varos ?? "ismeretlen";
console.log(varos);                 // "ismeretlen"

Van hozzá értékadó változat is: a ??= b csak akkor ír b-t a-ba, ha a null/undefined volt — „töltsd ki, ha üres":

let beallitasok = { tema: "sötét" };
beallitasok.tema ??= "világos";     // már van érték → marad "sötét"
beallitasok.nyelv ??= "hu";         // nincs → beírja
console.log(beallitasok);           // { tema: "sötét", nyelv: "hu" }
⚙️ HOL JÖN ELŐ NODE-BAN?

A szerver indításánál: const port = process.env.PORT ?? 3000; — ha a környezeti változó nincs beállítva, 3000. A kérés feldolgozásánál: const { nev, ar = 0 } = req.body; majd const kedvezmeny = req.body.kedvezmeny ?? 0; — itt a || hibás lenne, mert a 0% kedvezményt is „hiányzónak" venné. A válaszban: rendeles.vevo?.email ?? "nincs megadva".

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

Próbáld ki mindegyik szintaxist! Cseréld meg a spread-ek sorrendjét, adj alapértéket, vedd ki a ?.-t és nézd meg a hibaüzenetet. 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

Rövid függvények, amelyek mindegyike egy-egy modern szintaktikai elemet gyakoroltat. Mindegyik megoldható a régi módon is — de a cél most éppen a tömör, modern írásmód: destrukturálj, spread-elj, használd a ?.-t és a ??-t. Az Ellenőrzés a visszatérési értéket hasonlítja (objektumnál a mezők pontos halmazát!).

Gyakorló feladatok

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

Kész: 0 / 0
✅ NE MÓDOSÍTSD A KAPOTT ADATOT

Ahol a feladat „új objektumot" vagy „új tömböt" kér, tényleg újat készíts ({ ...o, … }, [...t, …]) — a paraméterként kapott eredetibe ne írj bele. Egy szerveren a kapott adatot sokan használják; aki csendben átírja, mások hibáját okozza.

11Összegzés

  1. Destrukturálás tömbből: const [a, b] = t — pozíció szerint; kihagyás vesszővel, alapérték = ertek, csere [a, b] = [b, a].
  2. Destrukturálás objektumból: const { nev, ar } = o — kulcs szerint; átnevezés { ar: egysegar }, alapérték { keszlet = 0 }, beágyazott { meret: { szel } }, paraméterlistában is: function f({ nev, ar }).
  3. Spread (... jobb oldalon): [...a, ...b] másol/összefűz, Math.max(...t) argumentumokká terít; { ...o, ar: 990 } = módosított másolat — a később írt mező nyer. Sekély másolat!
  4. Rest (... bal oldalon): function f(...args) bármennyi argumentum; const [elso, ...tobbi] = t, const { jelszo, ...nyilvanos } = o.
  5. Rövidítések: { nev, ar } (= { nev: nev, ar: ar }), számított kulcs { [kulcs]: ertek }, metódus nev() {}.
  6. ?. — ha a lánc egy pontja null/undefined, hiba helyett undefined; o?.[i], fn?.() is.
  7. ?? — alapérték csak null/undefined esetén (a || a 0-t és a ""-t is lecseréli!); a ??= b kitölti, ha üres.
  8. Változó: const alapból, let ha változik — var soha.
➡️ KÖVETKEZŐ LÉPÉS

A szintaxis megvan — most jön az adatfeldolgozás: a tömb-metódusok (map, filter, reduce, sort, some/every), amelyekkel egy webshop termékeit szűrjük, rendezzük, összesítjük és átalakítjuk — ciklus írása nélkül, láncolva. Pontosan ez történik egy API-végpont belsejében.