2.3 בקרת זרימה ולולאות הרצאה
תנאים - conditionals¶
if, else if, else¶
ב-JS התנאים עובדים אותו דבר כמו בפייתון, אבל עם תחביר שונה:
// JavaScript
let age = 20;
if (age >= 18) {
console.log("Adult");
} else if (age >= 13) {
console.log("Teenager");
} else {
console.log("Child");
}
# Python equivalent
age = 20
if age >= 18:
print("Adult")
elif age >= 13:
print("Teenager")
else:
print("Child")
ההבדלים העיקריים:
- ב-JS התנאי חייב להיות בסוגריים ()
- ב-JS הבלוק מוגדר על ידי { } ולא על ידי הזחה
- ב-JS אין elif - כותבים else if (שתי מילים)
- ב-JS אין נקודתיים : בסוף שורת התנאי
דוגמה נוספת:
let temperature = 35;
if (temperature > 30) {
console.log("Very hot!");
console.log("Drink water!");
} else if (temperature > 20) {
console.log("Nice weather");
} else if (temperature > 10) {
console.log("A bit cold");
} else {
console.log("Freezing!");
}
בלוק עם שורה אחת¶
כשיש רק שורה אחת בבלוק, אפשר לוותר על הסוגריים המסולסלים:
אבל לא מומלץ - תמיד עדיף להשתמש בסוגריים מסולסלים כדי למנוע טעויות.
תנאים מקוננים¶
let isLoggedIn = true;
let isAdmin = false;
if (isLoggedIn) {
if (isAdmin) {
console.log("Welcome, admin!");
} else {
console.log("Welcome, user!");
}
} else {
console.log("Please log in");
}
אותו דבר בפייתון:
# if is_logged_in:
# if is_admin:
# print("Welcome, admin!")
# else:
# print("Welcome, user!")
# else:
# print("Please log in")
switch - משפט בחירה¶
switch הוא אלטרנטיבה ל-if/else if כשיש הרבה אפשרויות לערך אחד:
let day = "Monday";
switch (day) {
case "Monday":
console.log("Start of the week");
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
console.log("Middle of the week");
break;
case "Friday":
console.log("Almost weekend!");
break;
case "Saturday":
case "Sunday":
console.log("Weekend!");
break;
default:
console.log("Invalid day");
}
switchבודק את הערך של הביטוי מול כלcase- חייבים לשים
breakאחרי כל case - אחרת הקוד ימשיך ל-case הבא (fall-through) defaultהוא מה שקורה אם אף case לא מתאים (כמוelse)- אפשר לקבץ cases כמו Tuesday/Wednesday/Thursday בדוגמה למעלה
בפייתון אין switch (עד גרסה 3.10 שהוסיפה match/case):
# Python 3.10+ equivalent
# match day:
# case "Monday":
# print("Start of the week")
# case "Friday":
# print("Almost weekend!")
fall-through - הטעות הכי נפוצה¶
let color = "red";
// WITHOUT break - bug!
switch (color) {
case "red":
console.log("Red"); // this runs
case "green":
console.log("Green"); // this ALSO runs! (fall-through)
case "blue":
console.log("Blue"); // this ALSO runs!
}
// prints: "Red", "Green", "Blue" - probably not what we wanted!
- בלי
break, הקוד "נופל" ל-case הבא ומריץ אותו גם - זה התנהגות מכוונת של השפה, אבל כמעט תמיד זו טעות
- תמיד שימו
breakאלא אם כן אתם רוצים fall-through בכוונה (כמו קיבוץ cases)
אופרטור תלת-תנאי - ternary operator¶
ראינו את זה בשיעור הקודם, בואו נעמיק:
// basic syntax: condition ? valueIfTrue : valueIfFalse
let age = 20;
let status = age >= 18 ? "adult" : "minor";
אפשר להשתמש בזה בתוך console.log:
אפשר לשרשר (אבל לא מומלץ - קשה לקריאה):
כלל אצבע: אם ה-ternary הופך למסובך, עדיף if/else רגיל. ternary טוב להשמות פשוטות.
בפייתון:
Guard Clauses - יציאה מוקדמת¶
טכניקה חשובה לכתיבת קוד נקי - במקום תנאים מקוננים, נבדוק את המקרים הפשוטים קודם ונצא:
// BAD - deeply nested
function processUser(user) {
if (user !== null) {
if (user.isActive) {
if (user.age >= 18) {
console.log("Processing user...");
// actual logic here
} else {
console.log("User is too young");
}
} else {
console.log("User is not active");
}
} else {
console.log("No user provided");
}
}
// GOOD - guard clauses
function processUser(user) {
if (user === null) {
console.log("No user provided");
return;
}
if (!user.isActive) {
console.log("User is not active");
return;
}
if (user.age < 18) {
console.log("User is too young");
return;
}
console.log("Processing user...");
// actual logic here - no nesting!
}
- במקום לקנן תנאים, בודקים את המקרים הבעייתיים ויוצאים עם
return - הקוד הראשי (ה-"happy path") נשאר בלי הזחה מיותרת
- הקוד הרבה יותר קריא
לולאות - loops¶
for - הלולאה הקלאסית¶
המבנה: for (initialization; condition; update)
- let i = 0 - אתחול: רץ פעם אחת בהתחלה
- i < 5 - תנאי: נבדק לפני כל סיבוב, הלולאה עוצרת כשזה false
- i++ - עדכון: רץ אחרי כל סיבוב
בפייתון:
הלולאה של JS יותר מפורשת אבל גם יותר גמישה:
// count backwards
for (let i = 10; i > 0; i--) {
console.log(i);
}
// prints: 10, 9, 8, ..., 1
// count by 2
for (let i = 0; i <= 10; i += 2) {
console.log(i);
}
// prints: 0, 2, 4, 6, 8, 10
בפייתון:
while - כל עוד¶
אותו דבר כמו בפייתון:
ההבדל: ב-JS התנאי בסוגריים () והבלוק ב-{ }.
do...while - לפחות פעם אחת¶
זו לולאה שלא קיימת בפייתון:
let input;
do {
input = prompt("Enter a number greater than 10:");
input = Number(input);
} while (input <= 10);
console.log("You entered:", input);
- הבלוק רץ לפחות פעם אחת - גם אם התנאי שקרי מההתחלה
- התנאי נבדק אחרי הריצה הראשונה
- שימושי כשצריך לבצע פעולה לפחות פעם אחת (למשל בקשת קלט מהמשתמש)
ההבדל מ-while רגיל:
// while - might not run at all
let x = 100;
while (x < 10) {
console.log(x); // never runs! condition is false from the start
x++;
}
// do...while - always runs at least once
let y = 100;
do {
console.log(y); // prints 100! runs once before checking condition
y++;
} while (y < 10);
בפייתון אין do...while. המקבילה:
# while True:
# input_val = input("Enter a number greater than 10: ")
# input_val = int(input_val)
# if input_val > 10:
# break
for...of - איטרציה על ערכים¶
for...of עובר על ערכים של אובייקט iterable (מערך, מחרוזת וכו'):
const colors = ["red", "green", "blue"];
for (const color of colors) {
console.log(color);
}
// prints: "red", "green", "blue"
זה מאוד דומה ל-for בפייתון:
עובד גם על מחרוזות:
const word = "Hello";
for (const char of word) {
console.log(char);
}
// prints: "H", "e", "l", "l", "o"
שימו לב שמשתמשים ב-const ולא let כי בכל סיבוב נוצר משתנה חדש.
for...in - איטרציה על מפתחות¶
for...in עובר על מפתחות (keys) של אובייקט:
const person = {
name: "Alice",
age: 25,
city: "Tel Aviv"
};
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
// prints:
// "name: Alice"
// "age: 25"
// "city: Tel Aviv"
בפייתון:
# person = {"name": "Alice", "age": 25, "city": "Tel Aviv"}
# for key in person:
# print(f"{key}: {person[key]}")
אזהרה: אל תשתמשו ב-for...in על מערכים! זה עובר על האינדקסים כמחרוזות, לא על הערכים:
const fruits = ["apple", "banana", "cherry"];
// DON'T do this with arrays
for (const index in fruits) {
console.log(index); // "0", "1", "2" (strings, not numbers!)
console.log(typeof index); // "string"
}
// DO this instead
for (const fruit of fruits) {
console.log(fruit); // "apple", "banana", "cherry"
}
סיכום: for...of מול for...in¶
| for...of | for...in | |
|---|---|---|
| עובר על | ערכים | מפתחות |
| לשימוש עם | מערכים, מחרוזות | אובייקטים |
| דוגמה | for (const x of [1,2,3]) |
for (const k in {a:1}) |
| מקבילה בפייתון | for x in list |
for k in dict |
break ו-continue¶
בדיוק כמו בפייתון:
break - יציאה מהלולאה¶
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // exit the loop when i is 5
}
console.log(i);
}
// prints: 0, 1, 2, 3, 4
continue - דילוג לסיבוב הבא¶
for (let i = 0; i < 10; i++) {
if (i % 2 === 0) {
continue; // skip even numbers
}
console.log(i);
}
// prints: 1, 3, 5, 7, 9
שילוב בלולאת while¶
let num = 0;
while (true) {
num++;
if (num % 3 === 0) {
continue; // skip multiples of 3
}
if (num > 10) {
break; // stop at 10
}
console.log(num);
}
// prints: 1, 2, 4, 5, 7, 8, 10
תוויות - labeled statements¶
ב-JS אפשר לתת שם (label) ללולאה ולהשתמש ב-break/continue כדי לצאת מלולאה חיצונית:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outer; // breaks out of BOTH loops
}
console.log(`i=${i}, j=${j}`);
}
}
// prints:
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
outer:הוא label - שם שנותנים ללולאהbreak outerיוצא מהלולאה שסומנה ב-outer:- בלי ה-label,
breakהיה יוצא רק מהלולאה הפנימית
בפייתון אין labels ללולאות. הדרך המקובלת היא להשתמש בפונקציה עם return או בדגל (flag):
# Python alternative (no labels)
# found = False
# for i in range(3):
# for j in range(3):
# if i == 1 and j == 1:
# found = True
# break
# if found:
# break
זה שימוש נדיר - בדרך כלל אפשר לכתוב את הקוד בצורה אחרת בלי labels.
דוגמה מסכמת¶
נכתוב תוכנית שמנחשת מספר:
// number guessing game
const secretNumber = Math.floor(Math.random() * 100) + 1; // random 1-100
let attempts = 0;
let guessed = false;
while (!guessed) {
let input = prompt("Guess a number between 1 and 100:");
// guard clause - user cancelled
if (input === null) {
console.log("Game cancelled!");
break;
}
let guess = Number(input);
attempts++;
// validate input
if (isNaN(guess) || guess < 1 || guess > 100) {
console.log("Please enter a valid number between 1 and 100");
continue; // skip to next iteration
}
if (guess === secretNumber) {
guessed = true;
alert(`Correct! The number was ${secretNumber}. You got it in ${attempts} attempts!`);
} else if (guess < secretNumber) {
console.log("Too low! Try higher.");
} else {
console.log("Too high! Try lower.");
}
}
// rate the player
switch (true) {
case attempts <= 3:
console.log("Amazing!");
break;
case attempts <= 7:
console.log("Good job!");
break;
case attempts <= 10:
console.log("Not bad");
break;
default:
console.log("Keep practicing!");
}
הדוגמה משלבת: while, if/else if/else, break, continue, switch ו-guard clause.
סיכום¶
- תנאים ב-JS: סוגריים
()סביב התנאי, סוגריים מסולסלים{ }סביב הבלוק,else ifבמקוםelif switchשימושי כשיש הרבה ערכים אפשריים - אל תשכחוbreak- הלולאה הקלאסית
forעם שלושה חלקים: אתחול, תנאי, עדכון while- כמו בפייתון,do...while- רץ לפחות פעם אחת (אין בפייתון)for...of- עובר על ערכים (למערכים) - כמוfor x in listבפייתוןfor...in- עובר על מפתחות (לאובייקטים) - כמוfor k in dictבפייתוןbreakו-continueעובדים כמו בפייתון- guard clauses הופכים קוד מקונן לקוד שטוח וקריא