Kihagyás

Függvények

Függvénydefiníció

JavaScriptben a function kulcsszóval definiálhatunk saját függvényeket. Ezt követően megadjuk a függvény nevét, majd zárójelek között a bementi paramétereket (ha vannak). A függvény törzsét kapcsos zárójelpár között adhatjuk meg. A függvényeinknek természetesen lehet visszatérési értéke is, ezt a return kulcsszó után adhatjuk meg.

A függvénydefiníció általános szintaxisa (a szögletes zárójelek közötti részek elhagyhatók):

1
2
3
4
function functionName([param1, param2, ...]) {
    // statements...
    [return returnValue;]
}

Bemeneti adatok ellenőrzése

Mivel a JavaScript dinamikusan típusos nyelv, így az egyes függvények meghívásakor nem tudhatjuk, hogy milyen típusú paramétereket kapunk. Egy statikusan típusos nyelvnél ez nem gond, de a JavaScript esetében, ha biztosra akarunk menni, érdemes ellenőrizni az egyes függvényparamétereket.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function evaluateGrade(grade) {
    // input validation
    if (typeof grade !== 'number' || grade < 1 || grade > 5) {
        return "Invalid grade! Please provide a number between 1 and 5.";
    }

    switch (grade) {
        case 1: return "Fail";
        case 2: return "Pass";
        case 3: return "Satisfactory";
        case 4: return "Good";
        case 5: return "Excellent";
        default: return "Unexpected error";
    }
}

console.log(evaluateGrade(5));  // "Excellent"
console.log(evaluateGrade(0));  // "Invalid grade! Please provide a number between 1 and 5."
console.log(evaluateGrade("5"));  // "Invalid grade! Please provide a number between 1 and 5."

Változók hatásköre (Scope) függvényekben

Fontos megérteni, hogyan viselkednek a változók a függvényeken belül:

  • let és const: Blokk szintű hatáskörrel rendelkeznek (block scope)
  • var: Függvény szintű hatáskörrel rendelkezik (function scope)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
function scopeExample() {
    var functionScoped = "I am function scoped";
    let blockScoped = "I am block scoped";
    const alsoBlockScoped = "I am also block scoped";

    if (true) {
        var functionScoped2 = "Still function scoped";
        let blockScoped2 = "Only accessible in this block";
        const alsoBlockScoped2 = "Also only in this block";
    }

    console.log(functionScoped2); // Works - var is function scoped
    // console.log(blockScoped2); // ERROR - let is block scoped
    // console.log(alsoBlockScoped2); // ERROR - const is block scoped
}

// console.log(functionScoped); // ERROR - all variables are local to the function

Függvényhívás és hoisting

Ha egy függvényt meg szeretnénk hívni JavaScriptben, akkor azt a szokásos szintaxissal tehetjük meg:

1
functionName([param1, param2, ...]);

Fontos különbség: A hagyományos function kulcsszóval definiált függvények esetén hoisting történik ("felemelés/felhúzás"), ami azt jelenti, hogy a definíciójuk előtt is meghívhatók:

1
2
3
4
5
6
// This works due to hoisting
sayHello(); // "Hello World!"

function sayHello() {
    console.log("Hello World!");
}

A hívás során átadjuk a függvénynek a bemeneti paramétereket (feltéve ha a kérdéses függvény vár paramétert).

Ha a függvényhívás során nem adjuk meg valamelyik függvényparaméter értékét, akkor az adott paraméter az undefined speciális értéket veszi fel.

1
2
3
4
5
function displayInfo(name, age) {
    console.log(name + " is " + age + " years old.");
}

displayInfo("John"); // age value: undefined

Kimenet

John is undefined years old.

Érdekes módon, ha több paraméterrel hívunk meg egy függvényt, mint amennyi paramétert vár, akkor a JavaScript erre nem dob hibát. Ekkor a "felesleges" paraméterek nemes egyszerűséggel figyelmen kívül lesznek hagyva.

1
2
3
4
5
function addNumbers(num1, num2) {
    return num1 + num2;
}

console.log(addNumbers(10, 20, 30, 40)); // the 30 and 40 parameters are ignored

Kimenet

30

Paraméterek meglétének ellenőrzése

Amint fentebb láthattuk, JavaScriptben gond nélkül megtehetjük azt, hogy a függvény egy adott paraméterének nem adunk át értéket a függvényhíváskor. Ezt több módon is ellenőrizhetjük:

Alapvető ellenőrzés

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function greet(name) {
    if (name === undefined) {
        console.log("Please provide a name to greet!");
    } else {
        console.log("Hello " + name + "!");
    }
}

greet();
greet("John");

Kimenet

Please provide a name to greet!

Hello John!

Általánosabb megoldás

A hagyományos ellenőrzés mellett lehetőségünk van egy másik ellenőrzési módszert is használni.

Az arguments egy speciális, tömb-szerű objektum, amely minden hagyományos JavaScript függvényben automatikusan elérhető. Ez az objektum tartalmazza az összes argumentumot, amelyet a függvény hívásakor átadtak neki, függetlenül attól, hogy a függvény definíciójában hány paramétert deklaráltunk. Bár tömb-szerű viselkedést mutat (van length tulajdonsága és számozott indexekkel férhetünk hozzá az elemeihez), valójában nem egy igazi tömb, ezért nem rendelkezik a tömbök összes metódusával.

Az arguments objektumot azért vezették be a JavaScript korai verzióiban, mert lehetővé tette a változó számú paraméterrel rendelkező függvények írását, amikor még nem léteztek a modern megoldások, mint a rest paraméterek (később).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function advancedGreet(name) {
    // Check if parameter exists and is not empty
    if (!name || typeof name !== 'string' || name === '') {
        console.log("Valid name is required!");
        return;
    }
    console.log("Hello " + name + "!");
}

// More defensive function
function safeGreet(name) {
    if (arguments.length === 0) {
        console.log("No parameters provided!");
        return;
    }

    if (typeof name !== 'string') {
        console.log("Name must be a string!");
        return;
    }

    console.log(`Hello ${name}!`);
}

Default paraméterek

JavaScriptben nincs function overload (még eltérő paraméterezés esetén sem). Ha két vagy több azonos nevű függvényünk van, akkor mindig a kódban legkésőbb definiált függvény lesz hívható.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function hello() {
    console.log("Hello!");
}

function hello(name) { // this will be the usable function
    console.log("Hello " + name + "!");
}

hello();
hello("John");

Kimenet

Hello undefined!

Hello John!

A kódban két hello névre hallgató függvényünk is van, ezért a fentebb leírtak alapján a legutoljára definiált, egy paramétert váró hello(name) függvény lesz hívható.

Szerencsére a default függvényparáméterek JavaScriptben is léteznek. Ezek segítségével már el tudjuk érni, hogy egy függvényt többféle eltérő paraméterezés mellett is használhassunk.

1
2
3
4
5
6
function hello(name = "World") {
    console.log("Hello " + name + "!");
}

hello();          // name value: "World"
hello("John");    // name value: "John"

Kimenet

Hello World!

Hello John!

Mivel a függvényhíváskor a paraméterek átadása JavaScriptben is "balról jobbra" történik, ezért a default értékkel rendelkező paraméterek mindig a paraméterlista jobb oldalán szerepeljenek.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function displayInfo(name, age = 25, profession = "developer") {
    console.log(`${name} is ${age} years old and works as a ${profession}.`);
}

displayInfo("John");
displayInfo("John", 30);
displayInfo("John", 30, "designer");

// Skip middle parameter using undefined
displayInfo("John", undefined, "teacher"); // age will be 25

Kimenet

John is 25 years old and works as a developer.

John is 30 years old and works as a developer.

John is 30 years old and works as a designer.

John is 25 years old and works as a teacher.

Rest paraméterek (Modern JavaScript)

A modern JavaScriptben használhatjuk a rest operátort (...) is, amely lehetővé teszi változó számú paraméter kezelését. Ebben az esetben a paraméter egy bejárható tömb lesz. Ennek használatáról később lesz szó.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function sum(...numbers) {
    let total = 0;
    for (const num of numbers) {
        total += num;
    }
    return total;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15

// Combining regular and rest parameters
function greetMultiple(greeting, ...names) {
    for (const name of names) {
        console.log(`${greeting} ${name}!`);
    }
}

greetMultiple("Hello", "John", "Jane", "Bob");

Callback függvények

JavaScriptben gyakran előfordul, hogy egy függvényt egy másik függvény paramétereként használunk fel. Az ilyen függvényt nevezzük callback függvénynek.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function playMusic() {
    console.log("Let the music play!");
}

// A function that takes a callback parameter
function checkTime(hour, callback) {
    if (hour >= 22 || hour <= 6) {
        console.log("It's nighttime, neighbors are sleeping!");
    } else {
        callback(); // call the callback function
    }
}

// Function call: callback function is playMusic
checkTime(16, playMusic);

Kimenet

Let the music play!

Biztonságos callback kezelés

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function myCallback(param) {
    console.log("Callback function called with parameter: " + param);
}

function safeCallbackHandler(callback, param) {
    if (typeof callback === "function") {
        callback(param);
    } else {
        console.warn("Provided callback is not a function!");
    }
}

safeCallbackHandler(myCallback, "kitten");
safeCallbackHandler("not a function", "test"); // Safe handling

Kimenet

Callback function called with parameter: kitten

Provided callback is not a function!

JavaScript függvények egyéb megadási módjai

Anonim függvények (Function Expressions)

JavaScriptben a hagyományos függvénydefiniálás mellett a függvényeket egy kifejezésként is definiálhatjuk.

1
2
3
4
5
6
let addNumbers = function (a, b) { 
    return a + b; 
};

let result = addNumbers(10, 5);
console.log(result);

Kimenet

15

Fontos különbség a hoisting-ban:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// This works - function declaration is hoisted
sayHello1();

function sayHello1() {
    console.log("Hello World!");
}

// This doesn't work - function expression is not hoisted
// sayHello2(); // ERROR!

let sayHello2 = function() { 
    console.log("Hello World!"); 
};

sayHello2(); // This works

Arrow function-ök (ES6+)

Az ECMAScript 6 (ES6) szabványban bevezették az arrow function-öket az anonim függvények tömörebb megadására.

1
let myArrowFunction = (/* param1, param2, ... */) => { /* ... */ };

Példa: Különböző paraméter számú arrow function-ök

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let greet = () => { 
    console.log("Hello World!"); 
};

let favoriteFlavor = flavor => { 
    console.log("Our favorite ice cream flavor: " + flavor); 
};

let addNumbers = (a, b) => { 
    return a + b; 
};

// Short syntax for simple returns
let multiply = (a, b) => a * b;

greet();
favoriteFlavor("chocolate");
console.log(addNumbers(10, 5));
console.log(multiply(4, 3));

Kimenet

Hello World!

Our favorite ice cream flavor: chocolate

15

12

Haladó függvény technikák

Immediately Invoked Function Expression (IIFE)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// IIFE pattern - executes immediately
(function() {
    console.log("This runs immediately!");
})();

// IIFE with parameters
(function(name) {
    console.log("Hello " + name + "!");
})("World");

// Arrow function IIFE
(() => {
    console.log("Arrow IIFE!");
})();

Higher-order függvények

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Function that returns a function
function multiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

const double = multiplier(2);
const triple = multiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15

// Function that takes a function as parameter
function processArray(array, processor) {
    const result = [];
    for (const item of array) {
        result.push(processor(item));
    }
    return result;
}

const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]