פונקציות

פונקציה היא בלוק קוד שניתן לקרוא לו בשם ולהשתמש בו שוב ושוב.


הכרזה על פונקציה (Function Declaration)

// הגדרת הפונקציה
function sayHello() {
    console.log("שלום!");
}

// קריאה לפונקציה
sayHello();  // "שלום!"
sayHello();  // "שלום!" (אפשר לקרוא שוב ושוב)

מבנה התחביר

function functionName(parameters) {
    // גוף הפונקציה
    // קוד שמתבצע כשקוראים לפונקציה
}

פרמטרים (Parameters)

פרמטרים הם ערכים שהפונקציה מקבלת:

function greet(name) {
    console.log(`שלום ${name}!`);
}

greet("דן");    // "שלום דן!"
greet("דנה");   // "שלום דנה!"

// מספר פרמטרים
function add(a, b) {
    console.log(a + b);
}

add(5, 3);  // 8

פרמטרים עם ברירת מחדל

function greet(name = "אורח") {
    console.log(`שלום ${name}!`);
}

greet("דן");  // "שלום דן!"
greet();      // "שלום אורח!"

ערך מוחזר (Return)

פונקציות יכולות להחזיר ערך:

function add(a, b) {
    return a + b;
}

let result = add(5, 3);
console.log(result);  // 8

// שימוש ישיר בתוצאה
console.log(add(10, 20));  // 30
console.log(add(2, 3) * 2);  // 10

return עוצר את הפונקציה

function checkAge(age) {
    if (age < 0) {
        return "גיל לא תקין";  // הפונקציה נעצרת כאן
    }
    if (age < 18) {
        return "קטין";
    }
    return "בגיר";
}

console.log(checkAge(-5));  // "גיל לא תקין"
console.log(checkAge(15));  // "קטין"
console.log(checkAge(25));  // "בגיר"

פונקציה ללא return מחזירה undefined

function doSomething() {
    console.log("עושה משהו");
    // אין return
}

let result = doSomething();
console.log(result);  // undefined

Function Expression

דרך נוספת להגדיר פונקציה - כערך במשתנה:

const greet = function(name) {
    return `שלום ${name}!`;
};

console.log(greet("דן"));  // "שלום דן!"

ההבדל מ-Declaration

// Declaration - אפשר לקרוא לפני ההגדרה (hoisting)
sayHi();  // עובד!
function sayHi() {
    console.log("היי!");
}

// Expression - אי אפשר לקרוא לפני ההגדרה
sayBye();  // ❌ שגיאה!
const sayBye = function() {
    console.log("ביי!");
};

Arrow Functions (=>)

תחביר מקוצר ומודרני לפונקציות:

// פונקציה רגילה
const add = function(a, b) {
    return a + b;
};

// Arrow function
const addArrow = (a, b) => {
    return a + b;
};

// קיצור נוסף - return מרומז
const addShort = (a, b) => a + b;

console.log(addShort(5, 3));  // 8

כללי קיצור

// פרמטר אחד - אפשר בלי סוגריים
const double = x => x * 2;

// אפס פרמטרים - חייבים סוגריים ריקות
const sayHi = () => "היי!";

// גוף מרובה שורות - חייבים {} ו-return מפורש
const greet = (name) => {
    const message = `שלום ${name}`;
    return message + "!";
};

// החזרת אובייקט - חייבים סוגריים
const createUser = (name) => ({ name: name, active: true });

Callback Functions

פונקציה שמועברת כפרמטר לפונקציה אחרת:

function processData(data, callback) {
    console.log("מעבד נתונים...");
    const result = data * 2;
    callback(result);  // קריאה לפונקציה שהועברה
}

function showResult(value) {
    console.log(`התוצאה: ${value}`);
}

processData(5, showResult);  // "מעבד נתונים..." → "התוצאה: 10"

// עם arrow function
processData(10, (result) => console.log(result));  // 20

שימוש נפוץ ב-callbacks

// setTimeout - הרצה אחרי זמן
setTimeout(() => {
    console.log("עברו 2 שניות");
}, 2000);

// forEach - עבור כל איבר
[1, 2, 3].forEach(num => console.log(num));

// map - המרה
const doubled = [1, 2, 3].map(num => num * 2);

Scope (טווח)

Block Scope

function example() {
    let x = 10;  // נגיש רק בתוך הפונקציה

    if (true) {
        let y = 20;  // נגיש רק בתוך ה-if
        console.log(x);  // ✅ 10
        console.log(y);  // ✅ 20
    }

    console.log(x);  // ✅ 10
    console.log(y);  // ❌ שגיאה! y לא קיים כאן
}

Global Scope

let globalVar = "אני גלובלי";

function test() {
    console.log(globalVar);  // ✅ נגיש
}

test();  // "אני גלובלי"

Closure

function outer() {
    let count = 0;

    return function inner() {
        count++;
        return count;
    };
}

const counter = outer();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3
// inner "זוכרת" את count מ-outer

Hoisting

JavaScript מעלה הכרזות לתחילת הסקופ:

// Function Declaration - מועלת לגמרי
sayHello();  // ✅ עובד!
function sayHello() {
    console.log("שלום!");
}

// Function Expression - רק המשתנה מועלה
sayBye();  // ❌ שגיאה!
var sayBye = function() {
    console.log("ביי!");
};

// let/const מועלים, אבל אסור לגשת אליהם לפני ההכרזה
// (Temporal Dead Zone)
console.log(x);  // ❌ ReferenceError
let x = 5;

Rest Parameters (...)

קבלת מספר לא מוגבל של פרמטרים:

function sum(...numbers) {
    let total = 0;
    for (let num of numbers) {
        total += num;
    }
    return total;
}

console.log(sum(1, 2));        // 3
console.log(sum(1, 2, 3, 4));  // 10
console.log(sum());            // 0

// עם פרמטרים נוספים
function greetAll(greeting, ...names) {
    for (let name of names) {
        console.log(`${greeting} ${name}!`);
    }
}

greetAll("שלום", "דן", "דנה", "אבי");

Spread Operator (...)

פריסת מערך לפרמטרים:

function add(a, b, c) {
    return a + b + c;
}

const numbers = [1, 2, 3];
console.log(add(...numbers));  // 6 (במקום add(1, 2, 3))

// שימוש עם Math
const values = [5, 2, 8, 1];
console.log(Math.max(...values));  // 8
console.log(Math.min(...values));  // 1

פונקציות פנימיות מובנות

Math

Math.round(4.7);    // 5 (עיגול)
Math.floor(4.7);    // 4 (עיגול למטה)
Math.ceil(4.2);     // 5 (עיגול למעלה)
Math.abs(-5);       // 5 (ערך מוחלט)
Math.random();      // מספר אקראי 0-1
Math.max(1, 5, 3);  // 5
Math.min(1, 5, 3);  // 1
Math.sqrt(16);      // 4 (שורש)
Math.pow(2, 3);     // 8 (חזקה)

String

"hello".toUpperCase();  // "HELLO"
"HELLO".toLowerCase();  // "hello"
"hello".includes("ell");  // true
"hello".startsWith("he"); // true
"hello".slice(0, 2);      // "he"
"a,b,c".split(",");       // ["a", "b", "c"]

Number

parseInt("42");       // 42
parseFloat("3.14");   // 3.14
(3.14159).toFixed(2); // "3.14"
Number.isInteger(5);  // true
Number.isNaN(NaN);    // true

דוגמאות מעשיות

פונקציית חישוב מחיר

function calculateTotal(price, quantity = 1, discount = 0) {
    const subtotal = price * quantity;
    const discountAmount = subtotal * (discount / 100);
    return subtotal - discountAmount;
}

console.log(calculateTotal(100));           // 100
console.log(calculateTotal(100, 3));        // 300
console.log(calculateTotal(100, 3, 10));    // 270

פונקציית אימות אימייל

const isValidEmail = (email) => {
    return email.includes("@") && email.includes(".");
};

console.log(isValidEmail("[email protected]"));  // true
console.log(isValidEmail("invalid"));           // false

מחולל סיסמאות

function generatePassword(length = 8) {
    const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    let password = "";

    for (let i = 0; i < length; i++) {
        const randomIndex = Math.floor(Math.random() * chars.length);
        password += chars[randomIndex];
    }

    return password;
}

console.log(generatePassword());    // "x7k2m9p1"
console.log(generatePassword(12));  // "a3b5c7d9e1f2"

סיכום

סוג תחביר דוגמה
Declaration function name() {} function add(a, b) { return a + b; }
Expression const name = function() {} const add = function(a, b) { return a + b; };
Arrow const name = () => {} const add = (a, b) => a + b;
Callback פונקציה כפרמטר arr.map(x => x * 2)

כללי אצבע: - השתמשו בשמות תיאוריים לפונקציות - פונקציה צריכה לעשות דבר אחד - השתמשו בערכי ברירת מחדל - החזירו ערך במקום לשנות משתנים גלובליים - Arrow functions מצוינות ל-callbacks קצרים

בדקו את עצמכם

נסו לענות לבד לפני שאתם פותחים את התשובה.

  1. מה מיוחד בפונקציית חץ לגבי this?

    1. אין לה this בכלל, והיא לוקחת את ה-this של הסביבה
    2. היא לא יכולה להחזיר ערך
    3. ה-this שלה תמיד window
    4. אין הבדל
    הצגת התשובה

    תשובה א. לכן פונקציית חץ נוחה ב-callbacks, ולא מתאימה כמתודה שצריכה את this של האובייקט.

  2. מה זה closure?

    1. שגיאת תחביר
    2. פונקציה שסוגרת את הדפדפן
    3. פונקציה ש"זוכרת" משתנים מהסביבה שבה נוצרה, גם אחרי שהסביבה הסתיימה
    4. לולאה סגורה
    הצגת התשובה

    תשובה ג. זה הבסיס למונים, ל-factory functions ולהרבה דפוסים ב-React.

  3. מה מחזירה פונקציה בלי return?

    1. null
    2. undefined
    3. שגיאה
    4. 0
    הצגת התשובה

    תשובה ב. פונקציה שלא מחזירה ערך במפורש מחזירה undefined.