Vezérlőpult
6. Tömbök · Építőkövek

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

Tömbök

Eddig egy változó egy értéket tárolt. De mi van, ha egy webshop száz termékét kell kezelned? A tömb több értéket tárol sorba rendezve, egyetlen változóban: indexszel éred el az elemeket, ciklussal járod be, metódusokkal bővíted és szűkíted. Ebben a fejezetben a tömb alapműveleteit tanulod meg, és függvényeket írsz, amelyek tömböt kapnak és tömböt vagy számot adnak vissza.

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

Tanulási célok

1Mi a tömb? Index és length

A tömb (array) több értéket tárol sorba rendezve, egyetlen változóban. Szögletes zárójellel hozzuk létre, az elemeket vesszővel választjuk el. Egy tömbben bármilyen típus lehet, de a gyakorlatban egyféle „dolgot" tartunk benne:

const termekek = ["Egér", "Monitor", "Kábel"];
const arak = [6990, 45990, 1990];
const ures = [];                       // üres tömb — később töltjük fel

console.log(termekek);                 // [ 'Egér', 'Monitor', 'Kábel' ]
console.log(termekek.length);          // 3 — az elemek száma

Az elemeket indexszel érjük el, amely 0-tól indul. Az index bármilyen kifejezés lehet — ezért az utolsó elem a length - 1 helyen van:

console.log(termekek[0]);                    // Egér   (az első)
console.log(termekek[2]);                    // Kábel  (a harmadik)
console.log(termekek[termekek.length - 1]);  // Kábel  (az utolsó — mindig működik)
console.log(termekek.at(-1));                // Kábel  (ugyanaz, rövidebben; at(-2) az utolsó előtti)
console.log(termekek[3]);                    // undefined — nincs ilyen index, de NEM hiba!

termekek[1] = "Monitor 27\"";                  // elem módosítása index szerint
⚠️ A SZÁMOZÁS 0-TÓL INDUL

Az első elem indexe 0, egy 3 elemű tömb utolsó eleme a [2]. A [3] már túl van a végén — nem hibát kapsz, hanem undefined-ot, ami később, egy számításban okoz NaN-t. A ciklusfeltétel ezért mindig i < t.length, nem <=.

2Hozzáadás és eltávolítás

Négy metódus a tömb két végének kezelésére — mind a négy helyben módosítja a tömböt:

MetódusMit csinálMit ad vissza
push(elem)a végére tesz egy (vagy több) elemetaz új hosszt
pop()az utolsót eltávolítjaaz eltávolított elemet
unshift(elem)az elejére tesz egy elemetaz új hosszt
shift()az elsőt eltávolítjaaz eltávolított elemet
const kosar = ["Egér"];
kosar.push("Monitor");          // [ 'Egér', 'Monitor' ]
kosar.push("Kábel", "Laptop");  // [ 'Egér', 'Monitor', 'Kábel', 'Laptop' ]
kosar.unshift("Táska");         // [ 'Táska', 'Egér', 'Monitor', 'Kábel', 'Laptop' ]

let utolso = kosar.pop();       // utolso = 'Laptop', a tömb 4 elemű
let elso = kosar.shift();       // elso = 'Táska', a tömb 3 elemű
console.log(kosar);             // [ 'Egér', 'Monitor', 'Kábel' ]

A push a leggyakoribb: így építünk fel egy új tömböt ciklusban — üresről indulunk, és a megfelelő elemeket beletesszük. Ezt a mintát a feladatok fele használja.

3Keresés, kivágás, összefűzés

indexOf és includes

const arak = [6990, 45990, 1990];

console.log(arak.indexOf(1990));      // 2 — az első előfordulás indexe
console.log(arak.indexOf(100));       // -1 — nincs benne (ezt így jelzi!)
console.log(arak.includes(45990));    // true — csak azt mondja, benne van-e

Ha csak az érdekel, benne van-e, az includes olvashatóbb; ha az is, hogy hol, akkor indexOf. Mindkettő szigorú (===) egyenlőséggel keres.

slice — másolat, résztömb (NEM módosít)

A slice(kezdo, veg) új tömböt ad a kezdo indextől a veg indexig (a veg már nincs benne). Az eredeti tömb változatlan marad:

const t = [10, 20, 30, 40, 50];

console.log(t.slice(1, 3));    // [ 20, 30 ]      — az 1. és 2. index
console.log(t.slice(2));       // [ 30, 40, 50 ]  — a 2. indextől a végéig
console.log(t.slice(-2));      // [ 40, 50 ]      — az utolsó 2
console.log(t.slice());        // [ 10, 20, 30, 40, 50 ] — teljes MÁSOLAT
console.log(t);                // változatlan

splice — helyben töröl és/vagy beszúr (MÓDOSÍT)

A splice(index, hany, ...ujak) az index-től hany elemet kivesz az eredeti tömbből, és a helyükre beszúrja az esetleges további argumentumokat. A kivett elemeket adja vissza:

const t = [10, 20, 30, 40, 50];

const kivett = t.splice(1, 2);   // az 1. indextől 2 elemet töröl
console.log(kivett);            // [ 20, 30 ]
console.log(t);                 // [ 10, 40, 50 ]  — az eredeti MEGVÁLTOZOTT

t.splice(1, 0, 99);             // 0 törlés + beszúrás az 1. indexre
console.log(t);                 // [ 10, 99, 40, 50 ]

t.splice(2, 1);                 // egy elem törlése index szerint (a 40)
console.log(t);                 // [ 10, 99, 50 ]
⚠️ slice ≠ splice

Egy betű a különbség, de az egyik másol (slice, „szelet"), a másik kivág az eredetiből (splice, „összefércel"). Ha a függvényednek új tömböt kell visszaadnia és az eredetit nem bánthatja, slice-t vagy push-os felépítést használj.

join — tömbből szöveg

const nevek = ["Egér", "Monitor", "Kábel"];
console.log(nevek.join(", "));    // Egér, Monitor, Kábel
console.log(nevek.join(""));      // EgérMonitorKábel
console.log([2, 0, 2, 5].join("-"));   // 2-0-2-5

4reverse és sort — a számok buktatója

Mindkettő helyben rendezi át a tömböt (és a tömböt magát adja vissza). A reverse() megfordítja a sorrendet; a sort() rendez — de van egy híres csapdája:

const nevek = ["körte", "alma", "szilva"];
nevek.sort();
console.log(nevek);          // [ 'alma', 'körte', 'szilva' ] — szövegnél jó

const szamok = [100, 25, 3, 40];
szamok.sort();
console.log(szamok);         // [ 100, 25, 3, 40 ] ← ROSSZ! "1" < "2" < "3" < "4" — szövegként hasonlított
⛔ A sort() ALAPBÓL SZÖVEG SZERINT RENDEZ

Argumentum nélkül a sort minden elemet szöveggé alakít, és „ábécé" szerint rendez — így a 100 a 25 elé kerül, mert az "1" kisebb, mint a "2". Számokhoz összehasonlító függvényt (comparator) kell adni.

A comparator egy callback (5. fejezet!), amely két elemet kap, és negatív számot ad, ha az első kerüljön előbbre, pozitívat, ha a második. Számoknál ez egyszerűen a kettő különbsége:

szamok.sort((a, b) => a - b);    // növekvő: [ 3, 25, 40, 100 ]
szamok.sort((a, b) => b - a);    // csökkenő: [ 100, 40, 25, 3 ]

const masolatRendezve = arak.slice().sort((a, b) => a - b);   // az eredeti arak marad

A comparatorral (pl. objektumok rendezése ár szerint) a 10. fejezetben foglalkozunk részletesen — most elég, ha a (a, b) => a - b mintát megjegyzed, és tudod, hogy számoknál kötelező.

5Bejárás és a három alapminta tömbön

A tömb elemein kétféleképpen megyünk végig. A for indexszel akkor kell, ha az indexre is szükség van (pozíció, szomszédos elem, visszafelé haladás); a for…of egyszerűbb, ha csak az elemek érdekelnek:

for indexszel
const arak = [6990, 45990, 1990];
for (let i = 0; i < arak.length; i++) {
  console.log(i + ". ár: " + arak[i]);
}
// 0. ár: 6990
// 1. ár: 45990
// 2. ár: 1990
for…of
const arak = [6990, 45990, 1990];
for (const ar of arak) {
  console.log(ar);
}
// 6990
// 45990
// 1990

A 4. fejezet három alapmintája (számlálás, összegzés, keresés) tömbön ugyanígy működik — csak most függvénybe csomagolva, amely a tömböt paraméterként kapja és az eredményt visszaadja:

function osszeg(t) {                // ÖSSZEGZÉS
  let s = 0;
  for (const x of t) {
    s += x;
  }
  return s;
}

function olcsokSzama(t, hatar) {    // SZÁMLÁLÁS feltétellel
  let db = 0;
  for (const ar of t) {
    if (ar < hatar) db++;
  }
  return db;
}

function legnagyobb(t) {            // KERESÉS: a legjobb eddig
  let max = t[0];                    // az első elemről indulunk
  for (let i = 1; i < t.length; i++) {
    if (t[i] > max) max = t[i];
  }
  return max;
}

function parosak(t) {               // SZŰRÉS: új tömb felépítése push-sal
  const uj = [];
  for (const x of t) {
    if (x % 2 === 0) uj.push(x);
  }
  return uj;
}

console.log(osszeg([6990, 45990, 1990]));       // 54970
console.log(olcsokSzama([6990, 45990, 1990], 10000));   // 2
console.log(parosak([1, 2, 3, 4]));            // [ 2, 4 ]
✅ A NÉGY MINTA, AMIBŐL A FELADATOK ÁLLNAK

Összegzés (gyűjtő 0-ról), számlálás (db++), legjobb-eddig (indulás az első elemről, csere ha jobb), új tömb felépítése (üres tömb + feltételes push). Ha egy feladatnál elakadsz, kérdezd meg: melyik a négy közül? A 10. fejezetben ezekre kapsz kész metódusokat (reduce, filter, map) — de csak akkor fogod érteni őket, ha most kézzel megírtad.

⚙️ HOL JÖN ELŐ NODE-BAN?

Az Express-kurzus első CRUD API-jában a terméklistát memóriában, egy tömbben tároljuk: a GET /termekek az egész tömböt küldi vissza, a POST push-ol bele, a DELETE /termekek/:id megkeresi az indexet és splice-szal kiveszi. Minden, amit itt kézzel megírsz, ott egy-egy útvonalkezelő törzse lesz.

6A tömb referencia — másolás

Egy szám vagy szöveg érték szerint kerül a változóba: let b = a után két független példány van. A tömb referencia: a változó nem a tömböt, hanem egy „címkét" tárol, amely a memóriában lévő tömbre mutat. Két változó tehát ugyanarra a tömbre mutathat:

const a = [1, 2, 3];
const b = a;             // NEM másolat: b ugyanarra a tömbre mutat
b.push(4);
console.log(a);          // [ 1, 2, 3, 4 ] — a is "megváltozott", mert ugyanaz a tömb
console.log(a === b);    // true

const c = a.slice();     // valódi másolat: új tömb ugyanazokkal az elemekkel
c.push(5);
console.log(a);          // [ 1, 2, 3, 4 ] — érintetlen
console.log(c);          // [ 1, 2, 3, 4, 5 ]
console.log(a === c);    // false — két külön tömb, még ha a tartalmuk egyezne is
ℹ️ const TÖMB — MÉGIS MÓDOSÍTHATÓ?

Igen. A const azt tiltja, hogy a változó másik tömbre mutasson (a = [9] hiba lenne), de a tömb tartalma szabadon változhat: a.push(4), a[0] = 7 rendben van. Ezért írjuk a tömböket általában const-tal.

Ugyanez történik függvénynek átadott tömbbel: a paraméter ugyanarra a tömbre mutat, így ha a függvény push-ol vagy sort-ol rajta, az a hívó tömbjét is megváltoztatja. A feladatokban, ahol „új tömböt" kérünk, ezért építs push-sal újat vagy indulj slice() másolatból — az eredeti maradjon érintetlen.

7Kétdimenziós tömb

A tömb eleme lehet egy másik tömb — így kapunk tömbök tömbjét, azaz táblázatot (mátrixot). A külső tömb a sorokat, a belsők az oszlopokat tartalmazzák; egy elemet két indexszel érünk el:

const matrix = [
  [1, 2, 3],     // 0. sor
  [4, 5, 6],     // 1. sor
  [7, 8, 9]      // 2. sor
];

console.log(matrix[1]);         // [ 4, 5, 6 ]  — az 1. sor (maga is tömb)
console.log(matrix[1][2]);      // 6           — 1. sor, 2. oszlop
console.log(matrix.length);     // 3 sor
console.log(matrix[0].length);  // 3 oszlop az első sorban

A bejárás két egymásba ágyazott ciklus (4. fejezet): a külső a sorokon, a belső egy sor elemein megy végig:

let osszeg = 0;
for (let s = 0; s < matrix.length; s++) {           // s: sor index
  let sorSzoveg = "";
  for (let o = 0; o < matrix[s].length; o++) {      // o: oszlop index az adott sorban
    sorSzoveg += matrix[s][o] + " ";
    osszeg += matrix[s][o];
  }
  console.log(sorSzoveg);        // 1 2 3  /  4 5 6  /  7 8 9
}
console.log(osszeg);             // 45

// for…of-fal ugyanez, ha nem kell az index:
for (const sor of matrix) {
  for (const elem of sor) { /* … */ }
}

Kétdimenziós tömb a webshopban: egy rendelés tételei soronként [ár, darab] párokként; egy heti eladási táblázat, ahol minden sor egy nap. A 7. fejezettől inkább objektumok tömbjét használjuk erre — de a két ciklus ugyanaz marad.

8Array.isArray és az üres tömb

A typeof egy tömbre "object"-et mond — ezért tömböt az Array.isArray-jel ellenőrzünk:

console.log(typeof [1, 2]);          // object — nem segít
console.log(Array.isArray([1, 2]));   // true
console.log(Array.isArray("abc"));    // false

Az üres tömb a leggyakoribb szélső eset, és a feladatokban mindig szerepel egy ilyen teszt. Gondold végig, mit adjon a függvényed, ha nincs elem: az összeg természetesen 0, de az átlag 0 / 0 = NaN lenne, a „legnagyobb" pedig t[0] = undefined. Ezeket egy guard clause-zal (5. fejezet) intézd el a függvény elején:

function atlag(t) {
  if (t.length === 0) {
    return 0;                   // üres tömb: megállapodás szerint 0
  }
  let s = 0;
  for (const x of t) s += x;
  return s / t.length;
}

console.log(atlag([]));           // 0 (NaN helyett)
console.log([].length === 0);     // true — így ellenőrizd az ürességet (a [] maga truthy!)
⚠️ AZ ÜRES TÖMB IGAZ ÉRTÉKŰ

if (t) egy üres tömbre is igaz, mert minden objektum truthy. Az ürességet mindig t.length === 0-val nézd.

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

Kísérletezz a tömbökkel: próbáld ki, mi módosítja az eredetit és mi ad újat, nézd meg a sort buktatóját, és járj be egy mátrixot. 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

Mint az előző fejezetben: egy megadott nevű függvényt írsz, az ellenőrző több argumentummal meghívja, és a visszaadott értéket hasonlítja a várthoz — tömböknél elemenként, sorrendben. A függvények tömböt kapnak paraméterként; csak ciklusokat és az itt tanult metódusokat használd (a map/filter/reduce még nem jött — ahol a leírás tiltja a reverse-t vagy az includes-t, ott a saját ciklusod a lényeg). Ahol „új tömböt" kérünk, az eredeti nem módosulhat. Minden feladatnál van üres vagy egyelemű tömbös teszt is!

Gyakorló feladatok

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

Kész: 0 / 0
✅ MELYIK MINTA?

Számot kell visszaadni → összegzés, számlálás vagy legjobb-eddig. Logikai értéket → keresés early return-nel. Tömböt → üres tömb + push (vagy slice másolat). Mátrixot → két ciklus. Előbb döntsd el, melyik, és csak aztán gépelj.

11Összegzés

  1. A tömb sorba rendezett értékek listája: [a, b, c]. Index 0-tól, elemszám length, utolsó elem t[t.length - 1] vagy t.at(-1). Nem létező index → undefined.
  2. Két vég: push/pop (vége), unshift/shift (eleje) — helyben módosítanak. Új tömböt [] + push-sal építünk.
  3. Keresés: indexOf (index vagy −1), includes (true/false). Kivágás: slice másol (nem módosít), splice helyben töröl/beszúr. join szöveget ad.
  4. reverse() és sort() helyben rendez át. A sort() alapból szöveg szerint — számokhoz sort((a, b) => a - b).
  5. Bejárás: for (let i = 0; i < t.length; i++) ha kell az index, for (const x of t) ha csak az elem. Minták: összegzés, számlálás, legjobb-eddig, új tömb felépítése.
  6. A tömb referencia: b = a nem másol, ugyanarra mutat; a.slice() valódi másolat. A const tömb tartalma módosítható, csak a változó nem mutathat másra.
  7. Kétdimenziós tömb = tömbök tömbje: m[sor][oszlop], bejárás két ciklussal. Array.isArray(x) mondja meg, tömb-e; az ürességet t.length === 0 jelzi — kezeld guard clause-zal.
➡️ KÖVETKEZŐ LÉPÉS

A tömb sorszámozott lista. A következő fejezetben az objektumokkal egy dolog nevesített tulajdonságait fogjuk össze: { nev: "Egér", ar: 6990, keszlet: 40 }. A kettő együtt — objektumok tömbje — a webshop terméklistája, és minden Node-os API adatformátuma.