Vezérlőpult
5. Függvények · Építőkövek

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

Függvények

A függvény egy névvel ellátott, újrahasználható kódblokk: egyszer megírod, és utána akárhányszor meghívhatod. Bemenetet (paramétereket) kaphat, és visszaadhat egy eredményt. Ettől a fejezettől a feladatokban is függvényeket írsz: az ellenőrző meghívja őket, és a return-nel visszaadott értéket nézi meg.

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

Tanulási célok

1Mi a függvény?

Képzeld a függvényt egy gépnek: beadsz neki valamit (bemenet), elvégez egy munkát, és kiad valamit (eredmény). A lényeg: egyszer megírod, sokszor használod. Az előző fejezet mintáit (számlálás, összegzés, keresés) eddig minden alkalommal újra le kellett gépelned — mostantól egy-egy függvénybe csomagolod, és csak a nevét hívod.

2Deklaráció és hívás

A függvényt a function kulcsszóval hozzuk létre (deklaráljuk), és a nevével + zárójellel hívjuk meg. A deklaráció önmagában nem futtat semmit — a törzs csak híváskor fut le:

// Létrehozás (deklaráció) — itt még nem történik semmi:
function koszont() {
  console.log("Helló!");
}

// Hívás — ekkor fut le a törzs:
koszont();   // Helló!
koszont();   // Helló!  (akárhányszor hívható)
⚠️ A ZÁRÓJEL HÍVJA MEG!

A koszont (zárójel nélkül) maga a függvény mint érték; a koszont() (zárójellel) a meghívása. Gyakori kezdő hiba lehagyni a zárójelet — akkor nem fut le semmi, csak „ránézünk" a függvényre. Ennek a különbségnek a 7. szakaszban még hasznát vesszük.

✅ NÉVADÁS

A függvény neve ige vagy „mit ad vissza" legyen, camelCase írásmóddal: brutto, kosarOsszeg, raktaronVan. A feladatokban a nevet az ellenőrző adja meg — pontosan úgy kell elnevezned, különben nem találja meg.

3Paraméterek, argumentumok, alapértelmezett érték

A függvény bemeneti adatokat kaphat. A definícióban felsorolt neveket paramétereknek, a híváskor ténylegesen átadott értékeket argumentumoknak hívjuk. A paraméter a függvényen belül egy közönséges lokális változó:

function koszont(nev) {                 // nev = paraméter
  console.log("Szia, " + nev + "!");
}

koszont("Anna");   // "Anna" = argumentum → Szia, Anna!
koszont("Béla");   // Szia, Béla!

function teglalapTerulet(a, b) {       // több paraméter vesszővel
  console.log(a * b);
}
teglalapTerulet(3, 5);   // 15 — a sorrend számít: a = 3, b = 5

Alapértelmezett paraméter

Ha egy argumentumot nem adunk át, a paraméter értéke undefined lesz. Ezt kerüli el az alapértelmezett érték, amely csak akkor lép életbe, ha az adott helyen nem érkezett argumentum:

function szallitasiDij(osszeg, dij = 990) {
  if (osszeg >= 20000) {
    return 0;                 // 20 000 Ft felett ingyenes
  }
  return dij;
}

szallitasiDij(5000);          // 990   (dij alapértelmezett)
szallitasiDij(5000, 1490);    // 1490  (megadtuk)
szallitasiDij(25000);         // 0
ℹ️ HA TÖBB VAGY KEVESEBB ARGUMENTUMOT ADSZ

A JavaScript nem szól: a fölösleges argumentumokat eldobja, a hiányzók undefined lesznek (vagy az alapértelmezett értéket kapják). Ezért az alapértelmezett paramétereket mindig a lista végére tedd.

4return — visszatérési érték és kilépés

A return kulcsszóval a függvény visszaad egy értéket, amellyel a hívás helyén tovább dolgozhatunk: eltároljuk, kiírjuk, vagy egy másik kifejezésbe tesszük. A függvényhívás így maga is egy kifejezés, amelynek értéke van:

function brutto(netto) {
  return Math.round(netto * 1.27);   // visszaadja az eredményt
}

let ar = brutto(6990);               // 8877 → eltároljuk
console.log(brutto(1000) + brutto(2000));   // 3810 → tovább számolunk vele
⛔ console.log ≠ return

A console.log csak kiír a konzolra, de nem ad vissza semmit. Ha egy függvényben nincs return (vagy üres a return;), a hívás értéke undefined. A feladatok ellenőrzője a visszaadott értéket nézi — ha csak kiírod az eredményt, a teszt elbukik!

❌ Csak kiír
function osszead(a, b) {
  console.log(a + b);
}
let x = osszead(2, 3);  // kiír 5-öt, de…
console.log(x);          // undefined
✅ Visszaad
function osszead(a, b) {
  return a + b;
}
let x = osszead(2, 3);
console.log(x * 10);     // 50

A return be is fejezi a függvényt

A return utáni sorok már nem futnak le. Ezt kihasználva a „rossz eseteket" a függvény elején elintézhetjük egy-egy korai kilépéssel (early return, guard clause) — a fő logika így nem kerül egyre mélyebb else ágakba:

function kedvezmenyesAr(ar, kupon) {
  if (kupon !== "NYAR10") {
    return ar;                         // nincs érvényes kupon → itt vége
  }
  return Math.round(ar * 0.9);          // ide csak érvényes kuponnal jutunk el
}

function prim(n) {
  if (n < 2) return false;              // guard: 0, 1, negatívak
  for (let i = 2; i < n; i++) {
    if (n % i === 0) return false;      // találtunk osztót → kilépünk a ciklusból ÉS a függvényből
  }
  return true;                           // a ciklus végigfutott: nincs osztó
}

Figyeld meg: a prim-ben nem kell a 4. fejezet „kapcsoló" változója és break-je — a return egyszerre lép ki a ciklusból és a függvényből.

5Függvénykifejezés és arrow function

A függvényt nem csak deklarációval hozhatod létre: egy változóba is beteheted. Ez a függvénykifejezés — a függvénynek itt nincs saját neve, a változó neve azonosítja:

const duplaz = function (x) {
  return x * 2;
};
console.log(duplaz(21));   // 42 — ugyanúgy hívjuk
ℹ️ HOISTING: MIKORTÓL HÍVHATÓ?

A function deklarációt a JavaScript a fájl elejére „emeli" (hoisting), így már a definíció előtti sorban is meghívhatod. A const f = function… vagy arrow kifejezés viszont csak a sora után létezik — előtte hívva hibát kapsz. Jó szokás: a függvényeket előbb definiáld, aztán használd, és akkor nem kell rá gondolnod.

Arrow function

Az arrow function (nyíl-függvény) a függvénykifejezés rövidebb írásmódja. Modern kódban — és a 10. fejezet tömb-metódusainál — ez a legelterjedtebb forma. Két alakja van:

// Blokkos alak: {} és return, mint a hagyományosnál
const brutto = (netto) => {
  const afa = netto * 0.27;
  return Math.round(netto + afa);
};

// Rövid alak: EGYETLEN kifejezés → a {} és a return elhagyható,
// a kifejezés értéke automatikusan a visszatérési érték
const duplaz = x => x * 2;             // egy paraméternél a zárójel is elhagyható
const osszead = (a, b) => a + b;        // több paraméternél kell a zárójel
const udvozlet = () => "Helló!";         // paraméter nélkül: üres zárójel

console.log(duplaz(5), osszead(2, 3), udvozlet());   // 10 5 Helló!
⚠️ RÖVID ALAKBAN NINCS return — BLOKKOSBAN KELL

x => x * 2 visszaadja az értéket. De ha kapcsos zárójelet nyitsz — x => { x * 2 } —, az már blokk, és return nélkül undefined-ot ad. Ha objektumot akarsz rövid alakban visszaadni, tedd zárójelbe: () => ({ nev: "Egér" }).

FormaPéldaMikor?
Deklarációfunction brutto(n) { … }„Fő" függvények, amelyeket név szerint hívsz — a feladatokban ezt kérjük
Függvénykifejezésconst f = function (n) { … };Ritkább; az arrow lényegében kiváltotta
Arrow, blokkosconst f = (n) => { … return …; };Több lépéses törzs, callbackként átadva
Arrow, rövidconst f = n => n * 2;Egykifejezéses átalakítás, feltétel — tömb-metódusoknál

6Hatókör (scope)

A hatókör szabályozza, hol látható egy változó. A let/const változó abban a blokkban ({ }) él, ahol létrehozták — ez lehet egy függvény törzse, egy if vagy egy ciklus. Kívülről nem érhető el:

let afakulcs = 1.27;               // GLOBÁLIS: mindenhonnan látszik

function brutto(netto) {
  let eredmeny = netto * afakulcs;  // LOKÁLIS: csak a függvényben él; afakulcs-ot "látja" kívülről
  return Math.round(eredmeny);
}

console.log(brutto(1000));       // 1270
console.log(eredmeny);           // HIBA: eredmeny is not defined

Árnyékolás (shadowing)

Ha a belső hatókörben ugyanolyan nevű változót hozol létre, mint kint, a belső elfedi a külsőt — a függvényen belül a sajátját látja, a külső érintetlen marad:

let nev = "Globális Géza";

function koszont() {
  let nev = "Lokális Lujza";     // árnyékolja a külsőt
  console.log(nev);              // Lokális Lujza
}
koszont();
console.log(nev);                // Globális Géza — nem változott
✅ ADAT BE PARAMÉTEREN, KI return-NEL

Kerüld, hogy a függvény globális változókat olvasgasson és módosítson. Kapja meg paraméterben, amire szüksége van, és return-nel adja vissza az eredményt. Így kiszámítható, önmagában tesztelhető — és pont ilyen függvényeket kér a gyakorló.

7A függvény mint érték: callback

JavaScriptben a függvény ugyanolyan érték, mint egy szám vagy szöveg: változóba tehető (ezt láttuk az arrow-nál), és átadható egy másik függvénynek argumentumként. Az így átadott függvényt callbacknek hívjuk: „hívj vissza, amikor kell". Nézd meg, hogyan ír egy saját ismetel függvény, amely valamit n-szer csinál — de hogy mit, azt a hívó dönti el:

function ismetel(n, fn) {        // fn: a callback paraméter
  for (let i = 1; i <= n; i++) {
    fn(i);                        // meghívjuk a kapott függvényt (zárójel!)
  }
}

function kiir(szam) {
  console.log("Kör: " + szam);
}

ismetel(3, kiir);                // átadjuk a kiir függvényt (zárójel NÉLKÜL — nem hívjuk, csak odaadjuk)
// Kör: 1, Kör: 2, Kör: 3

ismetel(2, i => console.log(i * 100));   // arrow function a helyszínen: 100, 200

Az ismetel(3, kiir) hívásban a kiir után nincs zárójel: nem az eredményét adjuk át, hanem magát a függvényt. Az ismetel belsejében aztán fn(i)-vel mi hívjuk meg. Ez a minta a következő fejezetek alapja: a 10. fejezetben a map, filter, sort mind egy callbacket vár, és ők döntik el, mikor és mivel hívják.

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

Az Express útvonalkezelői callback-függvények. Te megírod, mi történjen egy kérésnél, és az Express hívja meg, amikor befut egy ilyen kérés — pontosan úgy, ahogy az ismetel hívta az fn-t:

app.get('/termekek', (req, res) => {     // a 2. argumentum egy arrow function
  res.json(termekek);                     // az Express hívja meg, req és res argumentumokkal
});

A req (kérés) és res (válasz) a callback paraméterei — ugyanúgy, mint az i az ismetel-nél. Ha ezt a szakaszt érted, az Express-kurzus első napja már ismerős lesz.

8Tiszta függvény és rekurzió

Tiszta függvény

Egy függvény tiszta (pure), ha (1) ugyanarra a bemenetre mindig ugyanazt adja vissza, és (2) nincs mellékhatása: nem módosít külső változót, nem ír a konzolra, nem függ a dátumtól vagy véletlenszámtól. A tiszta függvény könnyen tesztelhető és kiszámítható — a feladatok mind ilyenek.

❌ Nem tiszta: külső állapotot módosít
let osszeg = 0;
function hozzaad(ar) {
  osszeg += ar;         // mellékhatás
}
hozzaad(100); hozzaad(100);
// az eredmény attól függ, hányszor hívták
✅ Tiszta: bemenet → kimenet
function brutto(netto) {
  return Math.round(netto * 1.27);
}
brutto(1000);   // 1270
brutto(1000);   // 1270 — mindig, bárhol, bárhányszor

Rekurzió — a függvény önmagát hívja

Egy függvény meghívhatja saját magát. Ez akkor természetes, ha a feladat egy „kisebb ugyanilyen" feladatra vezethető vissza. Klasszikus példa a faktoriális: 5! = 5 · 4!, és 4! = 4 · 3!… egészen 1! = 1-ig:

function faktorialis(n) {
  if (n <= 1) {
    return 1;                       // LEÁLLÁSI FELTÉTEL: itt már nem hívjuk újra
  }
  return n * faktorialis(n - 1);      // kisebb bemenettel hívjuk önmagát
}

console.log(faktorialis(5));    // 5 · 4 · 3 · 2 · 1 = 120
// faktorialis(5) → 5 * faktorialis(4) → 5 * 4 * faktorialis(3) → … → 5 * 4 * 3 * 2 * 1
⛔ LEÁLLÁSI FELTÉTEL NÉLKÜL VÉGTELEN

Rekurziónál mindig legyen egy ág, amely már nem hív újra (itt: n <= 1), és minden hívás közelítsen felé (itt: n - 1). Különben a hívások egymásra halmozódnak, míg a JavaScript Maximum call stack size exceeded hibával leáll — ez a rekurzió „végtelen ciklusa". Ugyanezt a faktoriálist ciklussal is meg lehet írni; a feladatokban bármelyik utat választhatod.

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

Írj és hívj meg függvényeket! Figyeld meg a return és a console.log különbségét, próbáld ki a korai kilépést, és adj át függvényt egy másik függvénynek. 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

Új feladattípus mostantól: minden feladatban egy megadott nevű függvényt írsz. Az ellenőrző több különböző argumentummal meghívja a függvényedet, és a visszaadott értéket (a return-t!) hasonlítja a várthoz — a console.log-ot nem nézi. A kiinduló kódban ott a függvény váza; a nevét és a paramétereit hagyd meg, csak a törzsét írd meg. Nyugodtan írhatsz segédfüggvényeket is mellé.

Gyakorló feladatok

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

Kész: 0 / 0
✅ HA A TESZT „undefined"-OT KAP

Szinte biztos, hogy hiányzik a return, vagy egy ág (pl. az else) nem ad vissza semmit. Nézd végig: minden lehetséges úton van-e return? Ciklus után is kell egy — az az eset, amikor a ciklus „nem talált semmit".

11Összegzés

  1. Függvény = névvel ellátott, újrahasználható kódblokk. function nev(param) { … } deklarálja, nev(arg) hívja — a zárójel hív, nélküle csak a függvény mint érték.
  2. Paraméter a definícióban, argumentum a hívásban. A hiányzó argumentum undefined; alapértelmezett érték: function f(x, y = 0).
  3. return visszaadja az értéket és befejezi a függvényt. return nélkül az eredmény undefined. Korai return = guard clause a rossz esetekre.
  4. Függvénykifejezés (const f = function…) és arrow function: x => x * 2 (rövid, automatikus return) vagy (a, b) => { …; return …; } (blokkos). Csak a deklarációt lehet a definíciója előtt hívni.
  5. Hatókör: a lokális változó és a paraméter csak a függvényen (blokkon) belül él; a belső név árnyékolja a külsőt. Adat be paraméteren, ki return-nel.
  6. A függvény érték: átadható argumentumként — ez a callback (ismetel(3, kiir)). Az Express útvonalkezelői is callbackek.
  7. Tiszta függvény: ugyanaz a bemenet → ugyanaz a kimenet, mellékhatás nélkül. Rekurzió: a függvény önmagát hívja — leállási feltétel kötelező.
➡️ KÖVETKEZŐ LÉPÉS

Eddig egy változó egy értéket tárolt. A következő fejezetben a tömbökkel sok értéket kezelünk egyszerre — a webshop terméklistája is egy tömb lesz. A függvényeid tömböt kapnak paraméterként, és ciklussal járják be; a most tanult callback-minta pedig a 10. fejezet tömb-metódusainál tér vissza.