2.4 פונקציות הרצאה
הגדרת פונקציה - function declaration¶
הדרך הבסיסית ביותר ליצור פונקציה ב-JS:
function greet(name) {
console.log(`Hello, ${name}!`);
}
greet("Alice"); // "Hello, Alice!"
greet("Bob"); // "Hello, Bob!"
בפייתון:
ההבדלים:
- function במקום def
- סוגריים מסולסלים { } במקום הזחה
- אין נקודתיים : בסוף השורה הראשונה
פונקציה עם ערך מוחזר - return¶
returnעובד בדיוק כמו בפייתון- אם אין
return, הפונקציה מחזירהundefined(בפייתון מחזירהNone)
function multiply(a, b) {
return a * b;
console.log("This will never run"); // dead code - after return
}
function doSomething() {
console.log("Hello");
// no return - returns undefined
}
let x = doSomething();
console.log(x); // undefined
הרמה - hoisting של function declarations¶
יתרון ייחודי של function declaration - אפשר לקרוא לפונקציה לפני שהיא מוגדרת בקוד:
// this works! function declarations are hoisted
sayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
בפייתון זה לא עובד:
זה שימושי כי אפשר לארגן את הקוד ככה שהקוד הראשי למעלה והפונקציות למטה.
ביטוי פונקציה - function expression¶
דרך נוספת ליצור פונקציה - לשמור אותה במשתנה:
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
greet("Alice"); // "Hello, Alice!"
- הפונקציה נשמרת בתוך משתנה, כמו כל ערך אחר
- הנקודה-פסיק בסוף חשובה כי זה assignment
- אין hoisting - אי אפשר לקרוא לפונקציה לפני ההגדרה
// this does NOT work - no hoisting for function expressions
// greet("Alice"); // ReferenceError: Cannot access 'greet' before initialization
const greet = function(name) {
console.log(`Hello, ${name}!`);
};
פונקציה אנונימית - anonymous function¶
הפונקציה בדוגמה למעלה היא "אנונימית" - אין לה שם. אפשר גם לתת לה שם:
const greet = function myGreeting(name) {
console.log(`Hello, ${name}!`);
};
greet("Alice"); // works
// myGreeting("Bob"); // ReferenceError - the name is only available inside the function
פונקציות חץ - arrow functions¶
תחביר מקוצר ומודרני ליצירת פונקציות (נוסף ב-ES6):
// regular function
const add = function(a, b) {
return a + b;
};
// arrow function
const addArrow = (a, b) => {
return a + b;
};
// arrow function with implicit return (one-liner)
const addShort = (a, b) => a + b;
כללי הקיצור:
1. מחליפים את function בחץ => אחרי הסוגריים
2. אם יש רק ביטוי אחד, אפשר לוותר על { } ועל return - הערך חוזר אוטומטית
3. אם יש רק פרמטר אחד, אפשר לוותר על הסוגריים:
// one parameter - parentheses optional
const double = x => x * 2;
const square = x => x ** 2;
// no parameters - empty parentheses required
const sayHi = () => console.log("Hi!");
// multiple parameters - parentheses required
const add = (a, b) => a + b;
// multiple lines - braces and return required
const calculate = (a, b) => {
let sum = a + b;
let product = a * b;
return { sum, product };
};
השוואה לפייתון¶
Arrow functions דומות ל-lambda בפייתון, אבל הרבה יותר חזקות:
// JavaScript arrow function
const double = x => x * 2;
// Python lambda (limited to one expression)
// double = lambda x: x * 2
- בפייתון
lambdaמוגבלת לביטוי אחד בלבד - ב-JS arrow function יכולה להכיל כמה שורות
מתי להשתמש בכל צורה?¶
// function declaration - for main/important functions
// hoisted, clear and readable
function processUser(user) {
// ...
}
// arrow function - for short callbacks and inline functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
// function expression - less common, when you need to conditionally define
const handler = isAdmin ? function() { /* ... */ } : function() { /* ... */ };
בפרקטיקה, רוב המפתחים משתמשים ב:
- function declaration לפונקציות עיקריות
- arrow functions לכל השאר
הבדלים חשובים בין סוגי הפונקציות¶
hoisting - הרמה¶
// function declaration - hoisted (works!)
sayHello();
function sayHello() {
console.log("Hello!");
}
// function expression - NOT hoisted (error!)
// sayBye(); // ReferenceError
const sayBye = function() {
console.log("Bye!");
};
// arrow function - NOT hoisted (error!)
// sayHi(); // ReferenceError
const sayHi = () => {
console.log("Hi!");
};
רק function declarations עוברות hoisting.
this - הקשר¶
ההבדל הכי חשוב בין פונקציה רגילה ל-arrow function הוא איך הן מתנהגות עם this. נלמד על this לעומק בשיעורים הבאים, אבל בקצרה:
// regular function - has its own 'this'
const person = {
name: "Alice",
greet: function() {
console.log(`Hello, I'm ${this.name}`);
}
};
person.greet(); // "Hello, I'm Alice"
// arrow function - inherits 'this' from surrounding scope
const person2 = {
name: "Bob",
greet: () => {
console.log(`Hello, I'm ${this.name}`); // 'this' is NOT person2!
}
};
person2.greet(); // "Hello, I'm undefined" (wrong!)
כלל אצבע: אל תשתמשו ב-arrow functions בתור methods של אובייקט.
arguments - אובייקט הארגומנטים¶
פונקציות רגילות מקבלות אובייקט מיוחד בשם arguments:
function showArgs() {
console.log(arguments);
console.log(arguments.length);
}
showArgs(1, 2, 3); // [1, 2, 3], 3
showArgs("a", "b"); // ["a", "b"], 2
// arrow functions don't have 'arguments'
const showArgsArrow = () => {
// console.log(arguments); // ReferenceError
};
argumentsמכיל את כל הארגומנטים שהועברו לפונקציה- Arrow functions לא מקבלות
arguments- משתמשים ב-rest parameters במקום
פרמטרים - parameters¶
ערכי ברירת מחדל - default parameters¶
function greet(name = "World") {
console.log(`Hello, ${name}!`);
}
greet("Alice"); // "Hello, Alice!"
greet(); // "Hello, World!"
בפייתון:
אותו רעיון בדיוק. אפשר גם בcombination:
function createUser(name, age = 0, role = "user") {
return { name, age, role };
}
createUser("Alice", 25, "admin"); // { name: "Alice", age: 25, role: "admin" }
createUser("Bob", 30); // { name: "Bob", age: 30, role: "user" }
createUser("Charlie"); // { name: "Charlie", age: 0, role: "user" }
פרמטרי rest - rest parameters¶
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
console.log(sum()); // 0
...numbersאוסף את כל הארגומנטים למערך- זה המקבילה של
*argsבפייתון
# Python equivalent
# def sum(*numbers):
# total = 0
# for num in numbers:
# total += num
# return total
אפשר לשלב rest parameters עם פרמטרים רגילים:
function log(level, ...messages) {
console.log(`[${level}]`, ...messages);
}
log("INFO", "Server started", "on port 3000");
// [INFO] Server started on port 3000
log("ERROR", "Something went wrong");
// [ERROR] Something went wrong
- ה-rest parameter חייב להיות האחרון ברשימת הפרמטרים
- יכול להיות רק rest parameter אחד
ערך מוחזר - return value¶
// returning a single value
function square(x) {
return x * x;
}
// returning an object (note the parentheses with arrow functions!)
const createPoint = (x, y) => ({ x, y });
// without () it would be treated as function body { }, not object { }
// returning nothing (void)
function logMessage(msg) {
console.log(msg);
// no return - returns undefined
}
// early return (guard clause)
function divide(a, b) {
if (b === 0) {
console.log("Cannot divide by zero!");
return null;
}
return a / b;
}
שימו לב לטריק עם arrow functions ואובייקטים:
// WRONG - JS thinks {} is function body
const makeObj = (x) => { value: x }; // returns undefined!
// CORRECT - wrap in () to indicate it's an object
const makeObj = (x) => ({ value: x }); // returns { value: x }
פונקציות כערכים מדרגה ראשונה - first-class functions¶
בדיוק כמו בפייתון, פונקציות ב-JS הן ערכים לכל דבר - אפשר לשמור אותן במשתנים, להעביר אותן כארגומנטים, ולהחזיר אותן מפונקציות אחרות:
// storing a function in a variable
const operation = add;
console.log(operation(3, 5)); // 8
// storing functions in an array
const operations = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b
];
console.log(operations[0](10, 3)); // 13 (add)
console.log(operations[2](10, 3)); // 30 (multiply)
// storing functions in an object
const math = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b
};
console.log(math.add(5, 3)); // 8
console.log(math.multiply(5, 3)); // 15
פונקציות חוזרות - callback functions¶
callback היא פונקציה שמעבירים כארגומנט לפונקציה אחרת, והיא "נקראת חזרה" בזמן מאוחר יותר:
function doSomething(callback) {
console.log("Doing something...");
callback(); // calling the function that was passed
}
doSomething(function() {
console.log("Done!");
});
// prints: "Doing something...", "Done!"
// same thing with arrow function
doSomething(() => {
console.log("Done!");
});
דוגמה מעשית יותר:
function processArray(arr, callback) {
const results = [];
for (const item of arr) {
results.push(callback(item));
}
return results;
}
const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
const squared = processArray(numbers, x => x ** 2);
console.log(squared); // [1, 4, 9, 16, 25]
const asStrings = processArray(numbers, x => String(x));
console.log(asStrings); // ["1", "2", "3", "4", "5"]
בפייתון זה אותו רעיון:
# def process_array(arr, callback):
# return [callback(item) for item in arr]
#
# doubled = process_array([1,2,3], lambda x: x * 2)
Callbacks הם הבסיס של תכנות אסינכרוני ב-JS - נראה הרבה מהם בהמשך הקורס.
setTimeout ו-setInterval¶
שתי פונקציות מובנות שמשתמשות ב-callbacks:
// setTimeout - run once after delay (milliseconds)
setTimeout(() => {
console.log("This runs after 2 seconds");
}, 2000);
// setInterval - run repeatedly every N milliseconds
let count = 0;
const intervalId = setInterval(() => {
count++;
console.log(`Tick ${count}`);
if (count >= 5) {
clearInterval(intervalId); // stop the interval
}
}, 1000);
setTimeoutמריץ callback פעם אחת אחרי עיכובsetIntervalמריץ callback שוב ושוב בכל N מילישניותclearIntervalעוצר interval שרץ
IIFE - ביטוי פונקציה שמופעל מיידית¶
IIFE (Immediately Invoked Function Expression) היא פונקציה שנוצרת ומופעלת מיד:
(function() {
console.log("This runs immediately!");
})();
// with arrow function
(() => {
console.log("This also runs immediately!");
})();
// with parameters
(function(name) {
console.log(`Hello, ${name}!`);
})("Alice");
למה זה שימושי?
- יוצר scope פרטי - משתנים בתוך ה-IIFE לא דולפים החוצה
- בעבר השתמשו בזה הרבה לפני שהיו let/const ומודולים
- היום פחות נפוץ, אבל עדיין שימושי לפעמים
// variables inside IIFE don't leak out
(function() {
let secret = "password123";
console.log(secret); // works inside
})();
// console.log(secret); // ReferenceError - not accessible outside
השוואה מסכמת לפייתון¶
| נושא | Python | JavaScript |
|---|---|---|
| הגדרת פונקציה | def name(): |
function name() { } |
| פונקציה אנונימית | lambda x: x * 2 |
(x) => x * 2 |
| ערך ברירת מחדל | def f(x=5): |
function f(x = 5) { } |
| ארגומנטים גמישים | def f(*args): |
function f(...args) { } |
| ערך מוחזר ללא return | None |
undefined |
| hoisting | לא | כן (רק function declaration) |
| first-class | כן | כן |
דוגמה מסכמת¶
// function declaration
function createGreeting(name, greeting = "Hello") {
return `${greeting}, ${name}!`;
}
// arrow function for short operations
const toUpperCase = str => str.toUpperCase();
const add = (a, b) => a + b;
// function that takes a callback
function repeat(n, callback) {
for (let i = 0; i < n; i++) {
callback(i);
}
}
// using callbacks
repeat(3, i => {
const msg = createGreeting("World");
console.log(`${i}: ${toUpperCase(msg)}`);
});
// prints:
// "0: HELLO, WORLD!"
// "1: HELLO, WORLD!"
// "2: HELLO, WORLD!"
// function that returns a function
function createMultiplier(factor) {
return (number) => number * factor;
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
סיכום¶
- שלוש דרכים ליצור פונקציות: declaration (
function), expression (const f = function), arrow (const f = () => {}) - רק function declarations עוברות hoisting
- arrow functions קצרות ונוחות, אבל מתנהגות שונה עם
this - ערכי ברירת מחדל:
function f(x = 5)- כמו בפייתון - rest parameters:
function f(...args)- כמו*argsבפייתון - פונקציות הן first-class - אפשר להעביר אותן כארגומנטים ולשמור במשתנים
- callbacks - העברת פונקציה כארגומנט - בסיס של תכנות אסינכרוני ב-JS
- IIFE - פונקציה שרצה מיד, יוצרת scope פרטי