מפתח

פרויקט לימוד שפת JavaScript בעברית, המיועד למתחילים עם דגש על סינטקס וצורת הכתיבה הנכונה.

מבנה הפרויקט

├── index.md           # קובץ זה
├── guides/             # מדריכים תיאורטיים
│   ├── 01_background.md
│   ├── 02_syntax.md
│   ├── 03_variables.md
│   ├── 04_operators.md
│   ├── 05_conditionals.md
│   ├── 06_loops.md
│   ├── 07_functions.md
│   ├── 08_arrays.md
│   ├── 09_objects.md
│   ├── 10_dom.md
│   ├── 11_events.md
│   ├── 12_async.md
│   ├── 13_fetch_api.md
│   └── 14_best_practices.md
└── examples/           # קבצי קוד לדוגמא
    ├── 01_basics.js
    ├── 02_variables.js
    ├── 03_operators.js
    ├── 04_conditionals.js
    ├── 05_loops.js
    ├── 06_functions.js
    ├── 07_arrays.js
    ├── 08_objects.js
    ├── 09_dom_example.html
    ├── 10_events_example.html
    ├── 11_async.js
    └── 12_fetch_example.html

איך להשתמש בפרויקט

הרצת קבצי JavaScript

# ב-Node.js
node examples/01_basics.js

# או בדפדפן דרך מסוף הפיתוח (DevTools Console)

צפייה בקבצי HTML

פתחו את קבצי ה-HTML בדפדפן כדי לראות את הדוגמאות בפעולה.

סדר לימוד מומלץ

  1. רקע והיסטוריה - הכרות עם השפה
  2. סינטקס בסיסי - כללי הכתיבה
  3. משתנים וטיפוסים - אחסון נתונים
  4. אופרטורים - פעולות חשבון והשוואה
  5. תנאים - קבלת החלטות בקוד
  6. לולאות - חזרה על פעולות
  7. פונקציות - ארגון קוד לשימוש חוזר
  8. מערכים - רשימות של נתונים
  9. אובייקטים - מבני נתונים מורכבים
  10. DOM - מניפולציה של דפי אינטרנט
  11. אירועים - תגובה לפעולות משתמש
  12. תכנות אסינכרוני - Promises ו-async/await
  13. קריאות שרת - עבודה עם APIs
  14. שיטות עבודה מומלצות - כתיבת קוד נקי

דרישות מקדימות

  • הבנה בסיסית של HTML ו-CSS
  • עורך קוד (מומלץ: VS Code)
  • דפדפן מודרני (Chrome, Firefox, Edge)
  • Node.js (להרצת קוד מחוץ לדפדפן)

רקע והיסטוריה של JavaScript

מה זה JavaScript?

JavaScript (בקיצור: JS) היא שפת תכנות דינמית המשמשת בעיקר לפיתוח אתרי אינטרנט אינטראקטיביים. היא אחת משלוש השפות הבסיסיות של פיתוח ווב:

שפה תפקיד
HTML מבנה הדף (תוכן)
CSS עיצוב הדף (מראה)
JavaScript התנהגות הדף (אינטראקטיביות)

היסטוריה קצרה

1995 - הלידה

  • נוצרה ב-10 ימים בלבד על ידי Brendan Eich בחברת Netscape
  • השם המקורי היה Mocha, לאחר מכן LiveScript, ולבסוף JavaScript

1997 - תקינה

  • הפכה לתקן בינלאומי בשם ECMAScript
  • מנוהלת על ידי ארגון ECMA International

2009 - Node.js

  • יצירת Node.js אפשרה להריץ JavaScript מחוץ לדפדפן
  • JavaScript הפכה לשפת Full-Stack

2015 - ES6/ES2015

  • עדכון משמעותי שהוסיף תכונות מודרניות רבות
  • מאז, גרסה חדשה יוצאת כל שנה

JavaScript לעומת Java

⚠️ חשוב להבין: JavaScript ו-Java הן שפות שונות לחלוטין!

JavaScript Java
שפה מפורשת (interpreted) שפה מהודרת (compiled)
typyng דינמי typing סטטי
מבוססת prototype מבוססת class
בעיקר לווב בעיקר לאפליקציות

השם "JavaScript" נבחר משיקולי שיווק בלבד, בגלל הפופולריות של Java באותה תקופה.


איפה JavaScript רצה?

1. בדפדפן (Browser)

┌─────────────────────────────────┐
│         דפדפן (Chrome)          │
│  ┌───────────────────────────┐  │
│  │      מנוע JavaScript      │  │
│  │         (V8)              │  │
│  └───────────────────────────┘  │
│                                 │
│  HTML ←→ CSS ←→ JavaScript      │
└─────────────────────────────────┘

כל דפדפן מודרני כולל מנוע JavaScript: - Chrome: V8 - Firefox: SpiderMonkey - Safari: JavaScriptCore (Nitro) - Edge: V8 (בעבר Chakra)

2. בשרת (Node.js)

┌─────────────────────────────────┐
│           Node.js               │
│  ┌───────────────────────────┐  │
│  │      מנוע JavaScript      │  │
│  │         (V8)              │  │
│  └───────────────────────────┘  │
│                                 │
│  גישה למערכת קבצים, רשת, וכו'  │
└─────────────────────────────────┘

למה ללמוד JavaScript?

פופולריות

  • השפה הפופולרית בעולם לפיתוח ווב
  • קהילה עצומה ותיעוד רב

גמישות

  • פיתוח Frontend (React, Vue, Angular)
  • פיתוח Backend (Node.js, Express)
  • אפליקציות מובייל (React Native)
  • אפליקציות דסקטופ (Electron)

נגישות

  • קל להתחיל - רק צריך דפדפן
  • תוצאות מיידיות וויזואליות
  • הרבה משאבי לימוד חינמיים

ביקוש בשוק העבודה

  • דרישה גבוהה למפתחי JavaScript
  • מגוון רחב של אפשרויות קריירה

כלים נדרשים

עורך קוד

מומלץ: Visual Studio Code (VS Code) - חינמי - תוספים רבים ל-JavaScript - IntelliSense (השלמה אוטומטית)

דפדפן

כל דפדפן מודרני עם כלי פיתוח (DevTools): - F12 או Ctrl+Shift+I לפתיחה - לשונית Console להרצת קוד

Node.js (אופציונלי)

להרצת JavaScript מחוץ לדפדפן: - הורדה מ-nodejs.org - בדיקת התקנה: node --version


הקובץ הראשון שלך

אפשרות 1: בתוך HTML

<!DOCTYPE html>
<html>
<head>
    <title>הקוד הראשון שלי</title>
</head>
<body>
    <h1>שלום עולם!</h1>

    <script>
        // הקוד שלך כאן
        console.log("שלום עולם!");
        alert("זה עובד!");
    </script>
</body>
</html>

אפשרות 2: קובץ נפרד

<!-- index.html -->
<script src="script.js"></script>
// script.js
console.log("שלום מקובץ חיצוני!");

אפשרות 3: במסוף הדפדפן

  1. פתחו את DevTools (F12)
  2. עברו ללשונית Console
  3. הקלידו: console.log("שלום!")
  4. לחצו Enter

סיכום

  • JavaScript היא שפת התכנות העיקרית לפיתוח ווב
  • נוצרה ב-1995 והתפתחה מאז משמעותית
  • רצה בדפדפנים ובשרתים (Node.js)
  • קלה ללמידה עם תוצאות מיידיות
  • דרושה מאוד בשוק העבודה

סינטקס בסיסי של JavaScript

מבנה בסיסי של קוד

JavaScript מורכבת מפקודות (statements) שמבוצעות בזו אחר זו מלמעלה למטה.

// פקודה ראשונה
console.log("שלום");

// פקודה שנייה
console.log("עולם");

נקודה-פסיק (Semicolon)

נקודה-פסיק ; מסמנת סוף פקודה:

// עם נקודה-פסיק (מומלץ)
let name = "דן";
console.log(name);

// בלי נקודה-פסיק (עובד, אבל פחות מומלץ)
let age = 25
console.log(age)

💡 המלצה: השתמשו תמיד בנקודה-פסיק לבהירות ומניעת באגים.


הערות (Comments)

הערות הן טקסט שהמחשב מתעלם ממנו - מיועדות לתיעוד והסברים.

הערה בשורה אחת

// זו הערה - המחשב מתעלם ממנה
let x = 5; // אפשר גם בסוף שורה

הערה מרובת שורות

/*
    זו הערה ארוכה
    שמשתרעת על
    כמה שורות
*/
let y = 10;

מתי להשתמש בהערות?

// ✅ טוב - מסביר למה, לא מה
// מחשב מחיר עם הנחה של 10% ללקוחות ותיקים
let finalPrice = price * 0.9;

// ❌ לא טוב - מסביר את המובן מאליו
// מגדיר משתנה x שווה ל-5
let x = 5;

רגישות לאותיות (Case Sensitivity)

JavaScript מבדילה בין אותיות גדולות וקטנות:

// אלה שלושה משתנים שונים!
let name = "דן";
let Name = "דנה";
let NAME = "דני";

console.log(name);  // "דן"
console.log(Name);  // "דנה"
console.log(NAME);  // "דני"

⚠️ שימו לב: console.logConsole.LogCONSOLE.LOG


רווחים והזחות (Whitespace & Indentation)

JavaScript מתעלמת מרווחים מיותרים, אבל הזחות חשובות לקריאות:

// ❌ קשה לקריאה
if(age>18){console.log("בגיר")}

// ✅ קריא ומסודר
if (age > 18) {
    console.log("בגיר");
}

כללי הזחה

  • השתמשו ב-2 או 4 רווחים (עדיף דרך Tab)
  • כל בלוק קוד בתוך { } מוזח פנימה
  • היו עקביים לאורך כל הקוד
function greet(name) {
    if (name) {
        console.log("שלום " + name);
    } else {
        console.log("שלום אורח");
    }
}

console.log - הדפסה למסוף

הפקודה הכי חשובה למתחילים! מדפיסה מידע למסוף (Console).

שימוש בסיסי

console.log("שלום עולם!");        // טקסט
console.log(42);                   // מספר
console.log(true);                 // ערך בוליאני
console.log(3.14);                 // מספר עשרוני

הדפסת מספר ערכים

console.log("שמי", "דן");              // שמי דן
console.log("הגיל שלי:", 25);          // הגיל שלי: 25
console.log(1, 2, 3, 4, 5);            // 1 2 3 4 5

הדפסת משתנים

let name = "דנה";
let age = 30;

console.log(name);                     // דנה
console.log("שם:", name, "גיל:", age); // שם: דנה גיל: 30

Template Literals (מומלץ!)

let name = "דן";
let age = 25;

// שימוש ב-backticks (`) ו-${}
console.log(`שמי ${name} ואני בן ${age}`);
// פלט: שמי דן ואני בן 25

סוגי console נוספים

console.log("מידע רגיל");           // הדפסה רגילה
console.warn("אזהרה!");             // אזהרה (צהוב)
console.error("שגיאה!");            // שגיאה (אדום)
console.info("מידע");               // מידע
console.table([1, 2, 3]);           // הצגה כטבלה

בלוקים של קוד

בלוק קוד מוגדר על ידי סוגריים מסולסלים { }:

// בלוק של if
if (condition) {
    // קוד בתוך הבלוק
    console.log("התנאי התקיים");
}

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

// בלוק של לולאה
for (let i = 0; i < 5; i++) {
    // קוד שחוזר על עצמו
    console.log(i);
}

מילים שמורות (Reserved Words)

מילים ש-JavaScript משתמשת בהן ואסור להשתמש בהן כשמות משתנים:

// ❌ שגיאה! אלה מילים שמורות
let if = 5;
let function = "שלום";
let return = true;

// ✅ תקין
let myIf = 5;
let myFunction = "שלום";
let returnValue = true;

רשימה חלקית של מילים שמורות

break, case, catch, continue, debugger, default, delete,
do, else, finally, for, function, if, in, instanceof,
new, return, switch, this, throw, try, typeof, var,
void, while, with, class, const, let, export, import,
extends, static, super, yield

סדר הביצוע

הקוד מתבצע מלמעלה למטה, שורה אחרי שורה:

console.log("1 - ראשון");
console.log("2 - שני");
console.log("3 - שלישי");

// פלט:
// 1 - ראשון
// 2 - שני
// 3 - שלישי

יוצאי דופן

  • פונקציות - מוגדרות אבל לא רצות עד שקוראים להן
  • קוד אסינכרוני - יכול לרוץ מאוחר יותר
console.log("1");

function hello() {
    console.log("2 - בתוך הפונקציה");
}

console.log("3");
hello();  // קריאה לפונקציה
console.log("4");

// פלט:
// 1
// 3
// 2 - בתוך הפונקציה
// 4

איפה לכתוב JavaScript?

1. בתוך HTML (Inline)

<button onclick="alert('לחצת!')">לחץ עליי</button>

2. בתג script בתוך HTML

<script>
    console.log("שלום!");
</script>

3. בקובץ חיצוני (מומלץ!)

<!-- index.html -->
<script src="app.js"></script>
// app.js
console.log("שלום מקובץ חיצוני!");

💡 המלצה: תמיד השתמשו בקובץ חיצוני לקוד JavaScript.


סיכום כללי הסינטקס

כלל דוגמה
סיום פקודה let x = 5;
הערה בשורה // הערה
הערה מרובה /* הערה */
רגישות לאותיות name ≠ Name
הזחה 2 או 4 רווחים
בלוק קוד { ... }
הדפסה console.log(...)

משתנים וטיפוסי נתונים

מה זה משתנה?

משתנה הוא כמו קופסה עם שם שמאחסנת מידע. אפשר לשים בה ערך, לקרוא אותו, ולשנות אותו.

// יצירת משתנה בשם "age" עם הערך 25
let age = 25;

// קריאת הערך
console.log(age);  // 25

// שינוי הערך
age = 26;
console.log(age);  // 26

שלוש דרכים להכריז על משתנה

let - משתנה ניתן לשינוי

let name = "דן";
name = "דנה";      // ✅ מותר לשנות
console.log(name); // "דנה"

const - קבוע (לא ניתן לשינוי)

const PI = 3.14159;
PI = 3.14;         // ❌ שגיאה! אי אפשר לשנות const

const API_URL = "https://api.example.com";

var - הדרך הישנה (לא מומלץ)

var oldWay = "לא מומלץ להשתמש";
// var יש לו בעיות עם scope, עדיף let

ההבדלים בין let, const ו-var

תכונה let const var
שינוי ערך ✅ כן ❌ לא ✅ כן
Block scope ✅ כן ✅ כן ❌ לא
Hoisting ❌ לא זמין ❌ לא זמין ✅ זמין (undefined)
הכרזה מחדש ❌ לא ❌ לא ✅ כן

דוגמה ל-Block Scope

if (true) {
    let x = 10;
    var y = 20;
}

console.log(y);  // 20 - var נגיש מחוץ לבלוק
console.log(x);  // ❌ שגיאה! let לא נגיש מחוץ לבלוק

💡 כלל אצבע: השתמשו ב-const כברירת מחדל. השתמשו ב-let רק כשצריך לשנות את הערך.


כללים לשמות משתנים

מה מותר?

let name = "דן";           // ✅ אותיות
let age2 = 25;             // ✅ ספרות (לא בהתחלה)
let first_name = "דן";     // ✅ קו תחתון
let $price = 100;          // ✅ סימן דולר
let _private = "סודי";     // ✅ קו תחתון בהתחלה

מה אסור?

let 2name = "דן";          // ❌ מתחיל בספרה
let my-name = "דן";        // ❌ מקף
let my name = "דן";        // ❌ רווח
let for = "דן";            // ❌ מילה שמורה

מוסכמות שמות (Naming Conventions)

// camelCase - הכי נפוץ ב-JavaScript
let firstName = "דן";
let totalAmount = 100;
let isLoggedIn = true;

// SCREAMING_SNAKE_CASE - לקבועים
const MAX_SIZE = 100;
const API_KEY = "abc123";

// PascalCase - לclass וcomponents
class UserProfile { }
function UserCard() { }

טיפוסי נתונים פרימיטיביים (Primitives)

JavaScript מכילה 7 טיפוסים פרימיטיביים:

1. String - מחרוזת

let name = "דן";              // גרשיים כפולות
let city = 'תל אביב';         // גרש בודד
let greeting = `שלום ${name}`; // template literal

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

2. Number - מספר

let age = 25;           // מספר שלם
let price = 19.99;      // מספר עשרוני
let negative = -10;     // מספר שלילי
let big = 1000000;      // מספר גדול
let scientific = 2.5e6; // 2,500,000 (כתיב מדעי)

// ערכים מיוחדים
let infinity = Infinity;
let notANumber = NaN;   // Not a Number

3. Boolean - ערך אמת/שקר

let isActive = true;
let isLoggedIn = false;

// תוצאות של השוואות
let isAdult = age >= 18;     // true
let isEmpty = name === "";   // false

4. undefined - לא מוגדר

let x;
console.log(x);  // undefined

// משתנה שהוכרז אבל לא קיבל ערך
let user;
console.log(user);  // undefined

5. null - ריק במכוון

let user = null;  // אין משתמש כרגע

// ההבדל מ-undefined:
// undefined = לא הוגדר
// null = הוגדר במכוון כריק

6. Symbol - ייחודי

let id1 = Symbol("id");
let id2 = Symbol("id");

console.log(id1 === id2);  // false - כל Symbol ייחודי

7. BigInt - מספרים גדולים מאוד

let bigNumber = 9007199254740991n;
let anotherBig = BigInt("12345678901234567890");

typeof - בדיקת סוג

האופרטור typeof מחזיר את סוג המשתנה:

console.log(typeof "שלום");    // "string"
console.log(typeof 42);        // "number"
console.log(typeof true);      // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null);      // "object" (באג היסטורי!)
console.log(typeof {});        // "object"
console.log(typeof []);        // "object"
console.log(typeof function(){}); // "function"

המרות בין סוגים (Type Conversion)

המרה למחרוזת

let num = 42;
let str = String(num);      // "42"
let str2 = num.toString();  // "42"
let str3 = num + "";        // "42" (טריק)

המרה למספר

let str = "42";
let num = Number(str);      // 42
let num2 = parseInt(str);   // 42 (שלם)
let num3 = parseFloat("3.14"); // 3.14 (עשרוני)
let num4 = +str;            // 42 (טריק)

// מקרים מיוחדים
Number("abc");      // NaN
Number("");         // 0
Number(true);       // 1
Number(false);      // 0
Number(null);       // 0
Number(undefined);  // NaN

המרה לבוליאני

Boolean(1);         // true
Boolean(0);         // false
Boolean("שלום");    // true
Boolean("");        // false
Boolean(null);      // false
Boolean(undefined); // false

// ערכים שהם false (falsy):
// 0, "", null, undefined, NaN, false

// כל השאר הם true (truthy)

חיבור מחרוזות (String Concatenation)

let first = "שלום";
let last = "עולם";

// שיטה 1: אופרטור +
let full = first + " " + last;  // "שלום עולם"

// שיטה 2: Template Literals (מומלץ!)
let message = `${first} ${last}!`;  // "שלום עולם!"

// שימוש מתקדם ב-template literals
let name = "דן";
let age = 25;
let intro = `שמי ${name}.
אני בן ${age}.
בעוד 5 שנים אהיה בן ${age + 5}.`;

עבודה עם מחרוזות

let text = "שלום עולם";

// אורך
console.log(text.length);  // 9

// גישה לתו (0-indexed)
console.log(text[0]);      // "ש"
console.log(text.charAt(0)); // "ש"

// מציאת מיקום
console.log(text.indexOf("עולם")); // 5

// חיתוך
console.log(text.slice(0, 4));  // "שלום"
console.log(text.substring(5)); // "עולם"

// שינוי אותיות
let eng = "Hello";
console.log(eng.toUpperCase()); // "HELLO"
console.log(eng.toLowerCase()); // "hello"

// החלפה
console.log(text.replace("עולם", "JavaScript")); // "שלום JavaScript"

// פיצול
console.log("א,ב,ג".split(",")); // ["א", "ב", "ג"]

// הסרת רווחים
console.log("  שלום  ".trim()); // "שלום"

סיכום

טיפוס דוגמה typeof
String "שלום" "string"
Number 42, 3.14 "number"
Boolean true, false "boolean"
undefined undefined "undefined"
null null "object"
Symbol Symbol() "symbol"
BigInt 123n "bigint"

כללי אצבע: - השתמשו ב-const כברירת מחדל - השתמשו ב-let רק כשצריך לשנות - הימנעו מ-var - השתמשו ב-template literals למחרוזות

אופרטורים (Operators)

אופרטורים הם סמלים שמבצעים פעולות על ערכים. JavaScript מכילה מגוון רחב של אופרטורים.


אופרטורים אריתמטיים (Arithmetic)

פעולות מתמטיות בסיסיות:

let a = 10;
let b = 3;

console.log(a + b);   // 13 - חיבור
console.log(a - b);   // 7  - חיסור
console.log(a * b);   // 30 - כפל
console.log(a / b);   // 3.333... - חילוק
console.log(a % b);   // 1  - שארית (modulo)
console.log(a ** b);  // 1000 - חזקה (10³)

חיבור עם מחרוזות

console.log("שלום" + " " + "עולם");  // "שלום עולם"
console.log("מספר: " + 5);           // "מספר: 5"
console.log(5 + "5");                 // "55" (מחרוזת!)
console.log(5 - "2");                 // 3 (מספר!)

⚠️ זהירות: חיבור עם מחרוזת הופך הכל למחרוזת!


אופרטורי השמה (Assignment)

let x = 10;        // השמה בסיסית

x += 5;            // x = x + 5  → 15
x -= 3;            // x = x - 3  → 12
x *= 2;            // x = x * 2  → 24
x /= 4;            // x = x / 4  → 6
x %= 4;            // x = x % 4  → 2
x **= 3;           // x = x ** 3 → 8

טבלת אופרטורי השמה

אופרטור דוגמה שקול ל
= x = 5 x = 5
+= x += 5 x = x + 5
-= x -= 5 x = x - 5
*= x *= 5 x = x * 5
/= x /= 5 x = x / 5
%= x %= 5 x = x % 5
**= x **= 5 x = x ** 5

אופרטורי הגדלה והקטנה (Increment/Decrement)

let count = 5;

count++;           // count = count + 1 → 6
count--;           // count = count - 1 → 5

// ההבדל בין prefix ל-postfix
let a = 5;
console.log(a++);  // 5 (מחזיר ואז מגדיל)
console.log(a);    // 6

let b = 5;
console.log(++b);  // 6 (מגדיל ואז מחזיר)
console.log(b);    // 6

אופרטורי השוואה (Comparison)

מחזירים true או false:

let a = 5;
let b = "5";

// השוואת ערך בלבד (עם המרה)
console.log(a == b);   // true (5 == "5")
console.log(a != b);   // false

// השוואה מדויקת (ערך וסוג)
console.log(a === b);  // false (מספר ≠ מחרוזת)
console.log(a !== b);  // true

// השוואות נוספות
console.log(5 > 3);    // true - גדול מ
console.log(5 < 3);    // false - קטן מ
console.log(5 >= 5);   // true - גדול או שווה
console.log(5 <= 4);   // false - קטן או שווה

== לעומת === (חשוב!)

// == - השוואה רופפת (עם המרת סוג)
console.log(5 == "5");     // true
console.log(0 == false);   // true
console.log(null == undefined); // true

// === - השוואה מדויקת (מומלץ!)
console.log(5 === "5");    // false
console.log(0 === false);  // false
console.log(null === undefined); // false

💡 המלצה: תמיד השתמשו ב-=== ו-!== למניעת באגים.


אופרטורים לוגיים (Logical)

&& - וגם (AND)

// מחזיר true רק אם שניהם true
console.log(true && true);   // true
console.log(true && false);  // false
console.log(false && true);  // false
console.log(false && false); // false

// דוגמה מעשית
let age = 25;
let hasLicense = true;
let canDrive = age >= 18 && hasLicense;  // true

|| - או (OR)

// מחזיר true אם לפחות אחד true
console.log(true || true);   // true
console.log(true || false);  // true
console.log(false || true);  // true
console.log(false || false); // false

// דוגמה מעשית
let isWeekend = true;
let isHoliday = false;
let dayOff = isWeekend || isHoliday;  // true

! - לא (NOT)

// הופך את הערך
console.log(!true);   // false
console.log(!false);  // true
console.log(!0);      // true
console.log(!"");     // true
console.log(!"שלום"); // false

// שימוש כפול להמרה לבוליאני
console.log(!!"שלום"); // true
console.log(!!0);      // false

?? - Nullish Coalescing

// מחזיר את הערך הימני רק אם השמאלי null או undefined
let name = null;
console.log(name ?? "אנונימי");  // "אנונימי"

let age = 0;
console.log(age ?? 18);  // 0 (לא null/undefined)
console.log(age || 18);  // 18 (0 הוא falsy!)

אופרטור טרנרי (Ternary)

קיצור ל-if/else בשורה אחת:

// תחביר: condition ? valueIfTrue : valueIfFalse

let age = 20;
let status = age >= 18 ? "בגיר" : "קטין";
console.log(status);  // "בגיר"

// דוגמאות נוספות
let score = 75;
let grade = score >= 90 ? "מצוין" :
            score >= 70 ? "טוב" :
            score >= 55 ? "מספיק" : "נכשל";
console.log(grade);  // "טוב"

// שימוש בפונקציות
function greet(name) {
    return name ? `שלום ${name}` : "שלום אורח";
}

אופרטורי מחרוזת

// חיבור מחרוזות
let first = "שלום";
let second = "עולם";
let full = first + " " + second;  // "שלום עולם"

// קיצור השמה
let text = "שלום";
text += " עולם";  // "שלום עולם"

// template literals
let name = "דן";
let greeting = `שלום ${name}!`;  // "שלום דן!"

אופרטור typeof

בודק את סוג הערך:

console.log(typeof 42);           // "number"
console.log(typeof "שלום");       // "string"
console.log(typeof true);         // "boolean"
console.log(typeof undefined);    // "undefined"
console.log(typeof null);         // "object" (באג!)
console.log(typeof {});           // "object"
console.log(typeof []);           // "object"
console.log(typeof function(){}); // "function"

סדר קדימויות (Operator Precedence)

כמו במתמטיקה, יש סדר לביצוע פעולות:

// כפל לפני חיבור
console.log(2 + 3 * 4);     // 14 (לא 20)
console.log((2 + 3) * 4);   // 20

// סדר הקדימויות (מהגבוה לנמוך):
// 1. () - סוגריים
// 2. ** - חזקה
// 3. *, /, % - כפל, חילוק, שארית
// 4. +, - - חיבור, חיסור
// 5. <, >, <=, >= - השוואות
// 6. ==, ===, !=, !== - שוויון
// 7. && - וגם
// 8. || - או
// 9. = - השמה

💡 טיפ: כשיש ספק, השתמשו בסוגריים לבהירות.


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

חישוב מחיר עם הנחה

let price = 100;
let discount = 20;  // אחוז
let finalPrice = price - (price * discount / 100);
console.log(finalPrice);  // 80

בדיקת גיל לאתר

let age = 16;
let hasParentPermission = true;
let canEnter = age >= 18 || (age >= 13 && hasParentPermission);
console.log(canEnter);  // true

חישוב ממוצע

let scores = [85, 90, 78, 92, 88];
let sum = scores[0] + scores[1] + scores[2] + scores[3] + scores[4];
let average = sum / scores.length;
console.log(average);  // 86.6

סיכום

סוג אופרטורים
אריתמטי + - * / % **
השמה = += -= *= /= %=
השוואה == === != !== > < >= <=
לוגי && \|\| ! ??
טרנרי ? :
סוג typeof
הגדלה/הקטנה ++ --

כללי אצבע: - השתמשו ב-=== במקום == - השתמשו ב-?? לבדיקת null/undefined - השתמשו בסוגריים לבהירות

תנאים (Conditionals)

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


if - תנאי בסיסי

let age = 20;

if (age >= 18) {
    console.log("אתה בגיר");
}

מבנה התחביר

if (condition) {
    // קוד שירוץ אם התנאי אמת (true)
}

if...else

let age = 15;

if (age >= 18) {
    console.log("אתה בגיר");
} else {
    console.log("אתה קטין");
}
// פלט: "אתה קטין"

if...else if...else

לבדיקת מספר תנאים:

let score = 75;

if (score >= 90) {
    console.log("מצוין");
} else if (score >= 80) {
    console.log("טוב מאוד");
} else if (score >= 70) {
    console.log("טוב");
} else if (score >= 55) {
    console.log("מספיק");
} else {
    console.log("נכשל");
}
// פלט: "טוב"

תנאים מקוננים (Nested)

let age = 25;
let hasLicense = true;

if (age >= 18) {
    if (hasLicense) {
        console.log("אתה יכול לנהוג");
    } else {
        console.log("צריך רישיון");
    }
} else {
    console.log("צעיר מדי");
}

גרסה נקייה יותר עם &&

if (age >= 18 && hasLicense) {
    console.log("אתה יכול לנהוג");
} else if (age >= 18) {
    console.log("צריך רישיון");
} else {
    console.log("צעיר מדי");
}

אופרטור טרנרי (Ternary)

קיצור ל-if/else בשורה אחת:

// תחביר: condition ? valueIfTrue : valueIfFalse

let age = 20;
let status = age >= 18 ? "בגיר" : "קטין";
console.log(status);  // "בגיר"

// שימוש ישיר
console.log(age >= 18 ? "מותר" : "אסור");

// שרשור (מספר תנאים)
let score = 85;
let grade = score >= 90 ? "A" :
            score >= 80 ? "B" :
            score >= 70 ? "C" :
            score >= 60 ? "D" : "F";

switch

לבדיקת ערך מול מספר אפשרויות:

let day = "שני";

switch (day) {
    case "ראשון":
        console.log("יום ראשון");
        break;
    case "שני":
        console.log("יום שני");
        break;
    case "שלישי":
        console.log("יום שלישי");
        break;
    default:
        console.log("יום אחר");
}
// פלט: "יום שני"

חשיבות break

let num = 2;

// בלי break - ימשיך לכל הcase-ים הבאים!
switch (num) {
    case 1:
        console.log("אחד");
    case 2:
        console.log("שתיים");
    case 3:
        console.log("שלוש");
}
// פלט: "שתיים" ואז "שלוש" (fall-through)

מספר ערכים לאותו קוד

let day = "שבת";

switch (day) {
    case "שישי":
    case "שבת":
        console.log("סוף שבוע!");
        break;
    default:
        console.log("יום עבודה");
}

Truthy ו-Falsy

ב-JavaScript, כל ערך הוא או truthy (נחשב אמת) או falsy (נחשב שקר).

ערכי Falsy (6 ערכים בלבד)

// כל אלה נחשבים false בתנאי:
false
0
"" (מחרוזת ריקה)
null
undefined
NaN

כל השאר הוא Truthy

// כל אלה נחשבים true:
true
1, -1, 3.14 (כל מספר שאינו 0)
"שלום" (כל מחרוזת שאינה ריקה)
"0" (מחרוזת עם אפס)
"false" (מחרוזת)
[] (מערך ריק)
{} (אובייקט ריק)
function() {} (פונקציה)

שימוש מעשי

let name = "";

if (name) {
    console.log(`שלום ${name}`);
} else {
    console.log("שלום אורח");
}
// פלט: "שלום אורח" (כי "" הוא falsy)

// בדיקה אם מערך לא ריק
let items = [1, 2, 3];
if (items.length) {
    console.log(`יש ${items.length} פריטים`);
}

Short-circuit Evaluation

|| - מחזיר את הערך הראשון ה-truthy

let name = "" || "אורח";
console.log(name);  // "אורח"

let user = null || undefined || "ברירת מחדל";
console.log(user);  // "ברירת מחדל"

// שימוש לערך ברירת מחדל
function greet(name) {
    name = name || "אורח";
    console.log(`שלום ${name}`);
}

&& - מחזיר את הערך הראשון ה-falsy

let result = "שלום" && "עולם";
console.log(result);  // "עולם" (שניהם truthy)

let result2 = "" && "עולם";
console.log(result2);  // "" (הראשון falsy)

// שימוש להרצת קוד בתנאי
let user = { name: "דן" };
user && console.log(user.name);  // "דן"

let nullUser = null;
nullUser && console.log(nullUser.name);  // לא ירוץ

?? - Nullish Coalescing

// מחזיר ימין רק אם שמאל null או undefined
let count = 0;
console.log(count || 10);   // 10 (0 הוא falsy!)
console.log(count ?? 10);   // 0 (0 אינו null/undefined)

let name = null;
console.log(name ?? "אנונימי");  // "אנונימי"

Optional Chaining (?.)

גישה בטוחה לתכונות מקוננות:

let user = {
    name: "דן",
    address: {
        city: "תל אביב"
    }
};

// בלי optional chaining
let city;
if (user && user.address) {
    city = user.address.city;
}

// עם optional chaining
let city2 = user?.address?.city;  // "תל אביב"

// אם משהו לא קיים
let nullUser = null;
console.log(nullUser?.name);  // undefined (ללא שגיאה!)

// עם פונקציות
let result = user.getName?.();  // undefined (אם אין פונקציה)

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

בדיקת סיסמה

function checkPassword(password) {
    if (!password) {
        return "נא להזין סיסמה";
    }
    if (password.length < 8) {
        return "הסיסמה קצרה מדי";
    }
    if (password.length > 20) {
        return "הסיסמה ארוכה מדי";
    }
    return "סיסמה תקינה";
}

תפריט משתמש

let role = "admin";

switch (role) {
    case "admin":
        console.log("גישה מלאה");
        break;
    case "editor":
        console.log("עריכת תוכן");
        break;
    case "viewer":
        console.log("צפייה בלבד");
        break;
    default:
        console.log("אין הרשאות");
}

חישוב מחיר עם הנחות

function calculatePrice(price, memberType) {
    let discount = 0;

    if (memberType === "gold") {
        discount = 20;
    } else if (memberType === "silver") {
        discount = 10;
    } else if (memberType === "bronze") {
        discount = 5;
    }

    return price - (price * discount / 100);
}

console.log(calculatePrice(100, "gold"));  // 80

סיכום

מבנה שימוש
if תנאי בסיסי
if...else תנאי עם אלטרנטיבה
if...else if...else מספר תנאים
? : תנאי קצר בשורה אחת
switch בדיקת ערך מול רשימה
&& ריצה בתנאי / ערך ראשון falsy
\|\| ברירת מחדל / ערך ראשון truthy
?? ברירת מחדל ל-null/undefined
?. גישה בטוחה לתכונות

לולאות (Loops)

לולאות מאפשרות לחזור על פעולות מספר פעמים ללא שכפול קוד.


for - לולאה קלאסית

הלולאה הכי נפוצה, כשיודעים כמה פעמים לחזור.

for (let i = 0; i < 5; i++) {
    console.log(i);
}
// פלט: 0, 1, 2, 3, 4

מבנה התחביר

for (initialization; condition; update) {
    // קוד שחוזר
}

// initialization - מתבצע פעם אחת בהתחלה
// condition - נבדק לפני כל איטרציה
// update - מתבצע אחרי כל איטרציה

דוגמאות

// ספירה לאחור
for (let i = 5; i >= 1; i--) {
    console.log(i);
}
// 5, 4, 3, 2, 1

// קפיצות של 2
for (let i = 0; i <= 10; i += 2) {
    console.log(i);
}
// 0, 2, 4, 6, 8, 10

// מעבר על מערך
let fruits = ["תפוח", "בננה", "תפוז"];
for (let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}

while - לולאה עם תנאי

ממשיכה כל עוד התנאי אמת.

let count = 0;

while (count < 5) {
    console.log(count);
    count++;
}
// פלט: 0, 1, 2, 3, 4

מתי להשתמש?

// כשלא יודעים מראש כמה פעמים
let input = "";
while (input !== "יציאה") {
    // קבל קלט מהמשתמש
    // input = prompt("הכנס טקסט:");
    console.log(input);
}

// חיפוש ערך
let numbers = [3, 7, 2, 9, 5];
let i = 0;
while (numbers[i] !== 9) {
    i++;
}
console.log(`מצאתי 9 במיקום ${i}`);

⚠️ זהירות: וודאו שהתנאי יהפוך ל-false מתישהו, אחרת תקבלו לולאה אינסופית!


do...while

כמו while, אבל מבצעת לפחות פעם אחת.

let count = 0;

do {
    console.log(count);
    count++;
} while (count < 5);
// פלט: 0, 1, 2, 3, 4

// ההבדל מ-while:
let x = 10;

while (x < 5) {
    console.log("while:", x);  // לא ירוץ!
}

do {
    console.log("do-while:", x);  // ירוץ פעם אחת!
} while (x < 5);

for...of - מעבר על איברים

לולאה מודרנית למעבר על מערכים ומחרוזות.

let fruits = ["תפוח", "בננה", "תפוז"];

for (let fruit of fruits) {
    console.log(fruit);
}
// תפוח, בננה, תפוז

// מעבר על מחרוזת
let word = "שלום";
for (let char of word) {
    console.log(char);
}
// ש, ל, ו, ם

יתרונות

  • קריא יותר
  • לא צריך לנהל אינדקס
  • עובד על כל iterable

for...in - מעבר על מפתחות

למעבר על מפתחות (keys) של אובייקטים.

let person = {
    name: "דן",
    age: 25,
    city: "תל אביב"
};

for (let key in person) {
    console.log(`${key}: ${person[key]}`);
}
// name: דן
// age: 25
// city: תל אביב

// גם עובד על מערכים (מחזיר אינדקסים)
let arr = ["a", "b", "c"];
for (let index in arr) {
    console.log(index);  // "0", "1", "2" (מחרוזות!)
}

💡 המלצה: השתמשו ב-for...of למערכים ו-for...in לאובייקטים.


break - יציאה מלולאה

עוצר את הלולאה לחלוטין:

for (let i = 0; i < 10; i++) {
    if (i === 5) {
        break;  // יציאה מהלולאה
    }
    console.log(i);
}
// פלט: 0, 1, 2, 3, 4

// חיפוש איבר
let numbers = [3, 7, 2, 9, 5];
let found = false;

for (let num of numbers) {
    if (num === 9) {
        found = true;
        break;
    }
}
console.log(found ? "נמצא!" : "לא נמצא");

continue - מעבר לאיטרציה הבאה

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

for (let i = 0; i < 5; i++) {
    if (i === 2) {
        continue;  // מדלג על 2
    }
    console.log(i);
}
// פלט: 0, 1, 3, 4

// הדפסת מספרים זוגיים בלבד
for (let i = 0; i <= 10; i++) {
    if (i % 2 !== 0) {
        continue;  // מדלג על אי-זוגיים
    }
    console.log(i);
}
// 0, 2, 4, 6, 8, 10

לולאות מקוננות (Nested)

לולאה בתוך לולאה:

// טבלת כפל
for (let i = 1; i <= 3; i++) {
    for (let j = 1; j <= 3; j++) {
        console.log(`${i} x ${j} = ${i * j}`);
    }
}
// 1x1=1, 1x2=2, 1x3=3, 2x1=2, 2x2=4...

// מעבר על מטריצה
let matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

for (let row of matrix) {
    for (let cell of row) {
        console.log(cell);
    }
}

break/continue בלולאות מקוננות

// break יוצא רק מהלולאה הפנימית
outer: for (let i = 0; i < 3; i++) {
    for (let j = 0; j < 3; j++) {
        if (i === 1 && j === 1) {
            break outer;  // יציאה מהלולאה החיצונית
        }
        console.log(i, j);
    }
}

מתודות של מערכים ללולאות

forEach

let fruits = ["תפוח", "בננה", "תפוז"];

fruits.forEach(function(fruit, index) {
    console.log(`${index}: ${fruit}`);
});
// 0: תפוח, 1: בננה, 2: תפוז

// עם arrow function
fruits.forEach((fruit) => console.log(fruit));

map

let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(num => num * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

filter

let numbers = [1, 2, 3, 4, 5, 6];
let evens = numbers.filter(num => num % 2 === 0);
console.log(evens);  // [2, 4, 6]

reduce

let numbers = [1, 2, 3, 4, 5];
let sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 15

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

מציאת ערך מקסימלי

let numbers = [23, 55, 12, 89, 34];
let max = numbers[0];

for (let num of numbers) {
    if (num > max) {
        max = num;
    }
}
console.log(max);  // 89

ספירת תווים

let text = "שלום עולם";
let count = 0;

for (let char of text) {
    if (char !== " ") {
        count++;
    }
}
console.log(`מספר תווים: ${count}`);  // 8

הפיכת מערך

let arr = [1, 2, 3, 4, 5];
let reversed = [];

for (let i = arr.length - 1; i >= 0; i--) {
    reversed.push(arr[i]);
}
console.log(reversed);  // [5, 4, 3, 2, 1]

סכום מספרים זוגיים

let sum = 0;
for (let i = 2; i <= 100; i += 2) {
    sum += i;
}
console.log(sum);  // 2550

השוואת סוגי לולאות

לולאה שימוש דוגמה
for כשיודעים כמה איטרציות for (let i = 0; i < 10; i++)
while כשהתנאי לא ידוע מראש while (input !== "exit")
do...while ריצה אחת לפחות do { ... } while (x > 0)
for...of מעבר על ערכים במערך for (let item of arr)
for...in מעבר על מפתחות באובייקט for (let key in obj)
forEach מעבר על מערך (מתודה) arr.forEach(item => ...)

סיכום

כללי אצבע: - השתמשו ב-for...of למערכים - השתמשו ב-for...in לאובייקטים - השתמשו ב-for קלאסי כשצריך אינדקס - השתמשו ב-while כשלא יודעים כמה איטרציות - זכרו לעדכן את התנאי למניעת לולאה אינסופית

פונקציות (Functions)

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


הכרזה על פונקציה (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 לא מועלים (זמינים רק אחרי ההכרזה)
console.log(x);  // ❌ שגיאה!
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 קצרים

מערכים (Arrays)

מערך הוא רשימה מסודרת של ערכים. אחד ממבני הנתונים החשובים ביותר ב-JavaScript.


יצירת מערך

// שיטה 1: סוגריים מרובעות (נפוץ)
let fruits = ["תפוח", "בננה", "תפוז"];

// שיטה 2: constructor (פחות נפוץ)
let numbers = new Array(1, 2, 3);

// מערך ריק
let empty = [];

// מערך עם סוגים מעורבים
let mixed = [1, "שלום", true, null, { name: "דן" }];

גישה לאיברים

מערכים מתחילים מאינדקס 0:

let fruits = ["תפוח", "בננה", "תפוז"];

console.log(fruits[0]);  // "תפוח"
console.log(fruits[1]);  // "בננה"
console.log(fruits[2]);  // "תפוז"
console.log(fruits[3]);  // undefined (לא קיים)

// האיבר האחרון
console.log(fruits[fruits.length - 1]);  // "תפוז"

// שינוי ערך
fruits[1] = "מנגו";
console.log(fruits);  // ["תפוח", "מנגו", "תפוז"]

אורך המערך (length)

let fruits = ["תפוח", "בננה", "תפוז"];

console.log(fruits.length);  // 3

// שימוש בלולאה
for (let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}

הוספה והסרה של איברים

push - הוספה לסוף

let fruits = ["תפוח", "בננה"];
fruits.push("תפוז");
console.log(fruits);  // ["תפוח", "בננה", "תפוז"]

// אפשר להוסיף כמה בבת אחת
fruits.push("מנגו", "ענבים");

pop - הסרה מהסוף

let fruits = ["תפוח", "בננה", "תפוז"];
let removed = fruits.pop();
console.log(removed);  // "תפוז"
console.log(fruits);   // ["תפוח", "בננה"]

unshift - הוספה להתחלה

let fruits = ["בננה", "תפוז"];
fruits.unshift("תפוח");
console.log(fruits);  // ["תפוח", "בננה", "תפוז"]

shift - הסרה מההתחלה

let fruits = ["תפוח", "בננה", "תפוז"];
let removed = fruits.shift();
console.log(removed);  // "תפוח"
console.log(fruits);   // ["בננה", "תפוז"]

splice - הוספה/הסרה ממיקום ספציפי

// התחביר: array.splice(start, deleteCount, items...)

let fruits = ["תפוח", "בננה", "תפוז", "מנגו"];

// הסרת 2 איברים מאינדקס 1
let removed = fruits.splice(1, 2);
console.log(removed);  // ["בננה", "תפוז"]
console.log(fruits);   // ["תפוח", "מנגו"]

// הוספה מבלי להסיר
fruits.splice(1, 0, "אבטיח");
console.log(fruits);  // ["תפוח", "אבטיח", "מנגו"]

// החלפה
fruits.splice(1, 1, "ענבים", "אננס");
console.log(fruits);  // ["תפוח", "ענבים", "אננס", "מנגו"]

slice - חיתוך (ללא שינוי המקור)

let fruits = ["תפוח", "בננה", "תפוז", "מנגו", "ענבים"];

// מאינדקס 1 עד 3 (לא כולל)
let sliced = fruits.slice(1, 3);
console.log(sliced);  // ["בננה", "תפוז"]
console.log(fruits);  // לא השתנה!

// מאינדקס 2 עד הסוף
console.log(fruits.slice(2));  // ["תפוז", "מנגו", "ענבים"]

// שלילי - מהסוף
console.log(fruits.slice(-2));  // ["מנגו", "ענבים"]

// העתקת מערך
let copy = fruits.slice();

חיפוש במערך

indexOf - מיקום ראשון

let fruits = ["תפוח", "בננה", "תפוז", "בננה"];

console.log(fruits.indexOf("בננה"));   // 1
console.log(fruits.indexOf("מנגו"));   // -1 (לא נמצא)

lastIndexOf - מיקום אחרון

let fruits = ["תפוח", "בננה", "תפוז", "בננה"];
console.log(fruits.lastIndexOf("בננה"));  // 3

includes - האם קיים

let fruits = ["תפוח", "בננה", "תפוז"];

console.log(fruits.includes("בננה"));  // true
console.log(fruits.includes("מנגו"));  // false

find - מציאת איבר לפי תנאי

let numbers = [5, 12, 8, 130, 44];

let found = numbers.find(num => num > 10);
console.log(found);  // 12 (הראשון שעונה על התנאי)

// עם אובייקטים
let users = [
    { id: 1, name: "דן" },
    { id: 2, name: "דנה" }
];
let user = users.find(u => u.id === 2);
console.log(user);  // { id: 2, name: "דנה" }

findIndex - אינדקס לפי תנאי

let numbers = [5, 12, 8, 130, 44];
let index = numbers.findIndex(num => num > 10);
console.log(index);  // 1

מתודות לולאה

forEach - מעבר על כל איבר

let fruits = ["תפוח", "בננה", "תפוז"];

fruits.forEach((fruit, index) => {
    console.log(`${index}: ${fruit}`);
});
// 0: תפוח
// 1: בננה
// 2: תפוז

map - יצירת מערך חדש מהמרה

let numbers = [1, 2, 3, 4, 5];

let doubled = numbers.map(num => num * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

// המערך המקורי לא משתנה
console.log(numbers);  // [1, 2, 3, 4, 5]

filter - סינון לפי תנאי

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let evens = numbers.filter(num => num % 2 === 0);
console.log(evens);  // [2, 4, 6, 8, 10]

let bigNumbers = numbers.filter(num => num > 5);
console.log(bigNumbers);  // [6, 7, 8, 9, 10]

reduce - צבירה לערך יחיד

let numbers = [1, 2, 3, 4, 5];

// סכום
let sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 15

// מקסימום
let max = numbers.reduce((acc, num) => num > acc ? num : acc);
console.log(max);  // 5

// ספירה
let words = ["שלום", "עולם", "שלום", "לכולם"];
let count = words.reduce((acc, word) => {
    acc[word] = (acc[word] || 0) + 1;
    return acc;
}, {});
console.log(count);  // { שלום: 2, עולם: 1, לכולם: 1 }

some - האם לפחות אחד עונה על התנאי

let numbers = [1, 2, 3, 4, 5];

console.log(numbers.some(num => num > 4));   // true
console.log(numbers.some(num => num > 10));  // false

every - האם כולם עונים על התנאי

let numbers = [2, 4, 6, 8];

console.log(numbers.every(num => num % 2 === 0));  // true
console.log(numbers.every(num => num > 5));        // false

מיון (sort)

// מיון אלפביתי
let fruits = ["תפוז", "בננה", "תפוח"];
fruits.sort();
console.log(fruits);  // ["בננה", "תפוז", "תפוח"]

// מיון מספרי - צריך פונקציית השוואה!
let numbers = [30, 4, 100, 21];
numbers.sort();
console.log(numbers);  // ❌ [100, 21, 30, 4] (מיון כמחרוזות!)

numbers.sort((a, b) => a - b);
console.log(numbers);  // ✅ [4, 21, 30, 100] (עולה)

numbers.sort((a, b) => b - a);
console.log(numbers);  // ✅ [100, 30, 21, 4] (יורד)

הפיכה (reverse)

let numbers = [1, 2, 3, 4, 5];
numbers.reverse();
console.log(numbers);  // [5, 4, 3, 2, 1]

חיבור מערכים

concat

let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = arr1.concat(arr2);
console.log(combined);  // [1, 2, 3, 4]

spread operator

let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = [...arr1, ...arr2];
console.log(combined);  // [1, 2, 3, 4]

// עם ערכים נוספים
let extra = [0, ...arr1, 2.5, ...arr2, 5];
console.log(extra);  // [0, 1, 2, 2.5, 3, 4, 5]

המרה למחרוזת (join)

let fruits = ["תפוח", "בננה", "תפוז"];

console.log(fruits.join());      // "תפוח,בננה,תפוז"
console.log(fruits.join(" "));   // "תפוח בננה תפוז"
console.log(fruits.join(" - ")); // "תפוח - בננה - תפוז"

Destructuring

פירוק מערך למשתנים:

let fruits = ["תפוח", "בננה", "תפוז"];

// במקום:
// let first = fruits[0];
// let second = fruits[1];

// אפשר:
let [first, second] = fruits;
console.log(first);   // "תפוח"
console.log(second);  // "בננה"

// דילוג על ערכים
let [a, , c] = fruits;
console.log(c);  // "תפוז"

// עם spread
let [head, ...rest] = fruits;
console.log(head);  // "תפוח"
console.log(rest);  // ["בננה", "תפוז"]

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

מציאת ממוצע

const average = (arr) => {
    const sum = arr.reduce((acc, num) => acc + num, 0);
    return sum / arr.length;
};

console.log(average([80, 90, 70, 85]));  // 81.25

הסרת כפילויות

const unique = (arr) => [...new Set(arr)];

console.log(unique([1, 2, 2, 3, 3, 3]));  // [1, 2, 3]

השטחת מערך

const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.flat();
console.log(flat);  // [1, 2, 3, 4, 5, 6]

סיכום מתודות

פעולה מתודה משנה מקור?
הוספה לסוף push()
הסרה מסוף pop()
הוספה להתחלה unshift()
הסרה מהתחלה shift()
הוספה/הסרה ממיקום splice()
חיתוך slice()
מיון sort()
הפיכה reverse()
המרה map()
סינון filter()
צבירה reduce()
חיפוש find()
חיבור concat()

אובייקטים (Objects)

אובייקט הוא אוסף של מאפיינים (properties) ומתודות (methods) המתארים ישות אחת.


יצירת אובייקט

Object Literal (נפוץ ביותר)

const person = {
    name: "דן",
    age: 25,
    city: "תל אביב"
};

מאפיינים עם שמות מיוחדים

const obj = {
    "first name": "דן",     // רווח - חייבים גרשיים
    "my-key": "value",      // מקף
    123: "מספר כמפתח"        // מספר
};

גישה למאפיינים

Dot Notation (נקודה)

const person = {
    name: "דן",
    age: 25
};

console.log(person.name);  // "דן"
console.log(person.age);   // 25

Bracket Notation (סוגריים)

console.log(person["name"]);  // "דן"

// חובה עבור שמות מיוחדים
const obj = { "first name": "דן" };
console.log(obj["first name"]);  // "דן"

// שימושי עם משתנים
const key = "name";
console.log(person[key]);  // "דן"

שינוי והוספת מאפיינים

const person = {
    name: "דן"
};

// שינוי ערך קיים
person.name = "דנה";

// הוספת מאפיין חדש
person.age = 25;
person["city"] = "תל אביב";

console.log(person);
// { name: "דנה", age: 25, city: "תל אביב" }

מחיקת מאפיין

const person = {
    name: "דן",
    age: 25,
    city: "תל אביב"
};

delete person.city;
console.log(person);  // { name: "דן", age: 25 }

מתודות (Methods)

מתודה היא פונקציה שמוגדרת בתוך אובייקט:

const person = {
    name: "דן",
    age: 25,

    // מתודה
    greet: function() {
        console.log("שלום!");
    },

    // קיצור מודרני
    sayAge() {
        console.log(`אני בן ${this.age}`);
    }
};

person.greet();   // "שלום!"
person.sayAge();  // "אני בן 25"

this

המילה this מתייחסת לאובייקט שבו נמצאת המתודה:

const person = {
    name: "דן",
    age: 25,

    introduce() {
        console.log(`שמי ${this.name} ואני בן ${this.age}`);
    }
};

person.introduce();  // "שמי דן ואני בן 25"

זהירות עם Arrow Functions!

const person = {
    name: "דן",

    // ❌ Arrow function - this לא עובד כמצופה!
    greetArrow: () => {
        console.log(this.name);  // undefined
    },

    // ✅ פונקציה רגילה
    greetRegular() {
        console.log(this.name);  // "דן"
    }
};

בדיקת קיום מאפיין

const person = {
    name: "דן",
    age: 25
};

// אופרטור in
console.log("name" in person);  // true
console.log("city" in person);  // false

// hasOwnProperty
console.log(person.hasOwnProperty("name"));  // true

// בדיקת ערך
console.log(person.city !== undefined);  // true אם קיים

מעבר על אובייקט

for...in

const person = {
    name: "דן",
    age: 25,
    city: "תל אביב"
};

for (let key in person) {
    console.log(`${key}: ${person[key]}`);
}
// name: דן
// age: 25
// city: תל אביב

Object.keys - רשימת מפתחות

const keys = Object.keys(person);
console.log(keys);  // ["name", "age", "city"]

Object.values - רשימת ערכים

const values = Object.values(person);
console.log(values);  // ["דן", 25, "תל אביב"]

Object.entries - זוגות [key, value]

const entries = Object.entries(person);
console.log(entries);
// [["name", "דן"], ["age", 25], ["city", "תל אביב"]]

// שימוש בלולאה
for (let [key, value] of Object.entries(person)) {
    console.log(`${key}: ${value}`);
}

Destructuring

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

const person = {
    name: "דן",
    age: 25,
    city: "תל אביב"
};

// במקום:
// const name = person.name;
// const age = person.age;

// אפשר:
const { name, age } = person;
console.log(name);  // "דן"
console.log(age);   // 25

// עם שינוי שם
const { name: userName, age: userAge } = person;
console.log(userName);  // "דן"

// עם ברירת מחדל
const { country = "ישראל" } = person;
console.log(country);  // "ישראל"

// אובייקטים מקוננים
const user = {
    name: "דן",
    address: {
        city: "תל אביב",
        street: "רוטשילד"
    }
};
const { address: { city } } = user;
console.log(city);  // "תל אביב"

Spread Operator

העתקת אובייקט

const original = { a: 1, b: 2 };
const copy = { ...original };

copy.a = 99;
console.log(original.a);  // 1 (לא השתנה)

מיזוג אובייקטים

const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged);  // { a: 1, b: 2, c: 3, d: 4 }

// עם override
const defaults = { color: "blue", size: "medium" };
const userSettings = { size: "large" };
const settings = { ...defaults, ...userSettings };
console.log(settings);  // { color: "blue", size: "large" }

Shorthand Properties

const name = "דן";
const age = 25;

// במקום:
const person1 = { name: name, age: age };

// אפשר:
const person2 = { name, age };
console.log(person2);  // { name: "דן", age: 25 }

Computed Property Names

const key = "dynamicKey";
const obj = {
    [key]: "ערך דינמי",
    [`prefix_${key}`]: "עם prefix"
};

console.log(obj.dynamicKey);        // "ערך דינמי"
console.log(obj.prefix_dynamicKey); // "עם prefix"

Object.assign

העתקה ומיזוג של אובייקטים:

const target = { a: 1 };
const source = { b: 2, c: 3 };

Object.assign(target, source);
console.log(target);  // { a: 1, b: 2, c: 3 }

// יצירת עותק
const copy = Object.assign({}, target);

Object.freeze ו-Object.seal

// freeze - לא ניתן לשנות, להוסיף או למחוק
const frozen = Object.freeze({ a: 1 });
frozen.a = 2;     // ❌ לא יעבוד
frozen.b = 3;     // ❌ לא יעבוד
delete frozen.a;  // ❌ לא יעבוד

// seal - ניתן לשנות, לא להוסיף או למחוק
const sealed = Object.seal({ a: 1 });
sealed.a = 2;     // ✅ עובד
sealed.b = 3;     // ❌ לא יעבוד
delete sealed.a;  // ❌ לא יעבוד

אובייקטים מקוננים

const company = {
    name: "TechCorp",
    employees: [
        { name: "דן", role: "developer" },
        { name: "דנה", role: "designer" }
    ],
    address: {
        city: "תל אביב",
        street: "רוטשילד",
        number: 42
    }
};

// גישה
console.log(company.address.city);  // "תל אביב"
console.log(company.employees[0].name);  // "דן"

// Optional Chaining
console.log(company.address?.zipCode);  // undefined (בלי שגיאה)

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

יצירת user factory

function createUser(name, age) {
    return {
        name,
        age,
        isAdult() {
            return this.age >= 18;
        },
        greet() {
            return `שלום, אני ${this.name}`;
        }
    };
}

const user = createUser("דן", 25);
console.log(user.greet());     // "שלום, אני דן"
console.log(user.isAdult());   // true

עדכון מאפיין בצורה אימטבילית

const user = { name: "דן", age: 25 };

// יצירת עותק עם שינוי
const updatedUser = { ...user, age: 26 };

console.log(user.age);         // 25 (לא השתנה)
console.log(updatedUser.age);  // 26

סיכום

פעולה תחביר
יצירה { key: value }
גישה obj.key או obj["key"]
הוספה/שינוי obj.key = value
מחיקה delete obj.key
בדיקת קיום "key" in obj
מפתחות Object.keys(obj)
ערכים Object.values(obj)
זוגות Object.entries(obj)
פירוק const { key } = obj
פריסה { ...obj }

DOM - Document Object Model

ה-DOM הוא ייצוג של דף ה-HTML כמבנה עץ שאפשר לגשת אליו ולשנות אותו עם JavaScript.


מה זה DOM?

כשדפדפן טוען דף HTML, הוא יוצר מודל אובייקטים:

document
└── html
    ├── head
    │   └── title
    └── body
        ├── h1
        ├── div
        │   └── p
        └── button

JavaScript יכולה לגשת לכל אלמנט ולשנות אותו!


בחירת אלמנטים

לפי ID (יחיד)

const element = document.getElementById("myId");
console.log(element);
<div id="myId">תוכן</div>

לפי Class (רשימה)

const elements = document.getElementsByClassName("myClass");
console.log(elements);  // HTMLCollection

// גישה לאיבר ספציפי
console.log(elements[0]);

לפי תגית (רשימה)

const paragraphs = document.getElementsByTagName("p");

לפי Selector (מודרני - מומלץ!)

// בחירת אלמנט אחד (הראשון)
const element = document.querySelector(".myClass");
const header = document.querySelector("#header");
const firstP = document.querySelector("div p");

// בחירת כל האלמנטים
const allButtons = document.querySelectorAll("button");
const allItems = document.querySelectorAll(".item");

// מעבר על התוצאות
allButtons.forEach(btn => {
    console.log(btn.textContent);
});

שינוי תוכן

textContent - טקסט בלבד

const element = document.querySelector("#title");

// קריאה
console.log(element.textContent);

// שינוי
element.textContent = "כותרת חדשה";

innerHTML - עם HTML

const container = document.querySelector("#container");

// הוספת HTML
container.innerHTML = "<strong>טקסט מודגש</strong>";

// תוספת לקיים
container.innerHTML += "<p>פסקה חדשה</p>";

⚠️ זהירות: innerHTML יכול להיות מסוכן אם מכניסים קלט משתמש (XSS)!

innerText

// דומה ל-textContent אבל מתחשב ב-CSS
element.innerText = "טקסט שייראה";

שינוי סגנון (Style)

const box = document.querySelector("#box");

// שינוי style יחיד
box.style.backgroundColor = "blue";
box.style.fontSize = "20px";
box.style.padding = "10px";
box.style.borderRadius = "5px";

// שים לב: camelCase במקום kebab-case
// CSS: background-color → JS: backgroundColor
// CSS: font-size → JS: fontSize

שינוי Classes

const element = document.querySelector("#element");

// הוספת class
element.classList.add("active");

// הסרת class
element.classList.remove("active");

// החלפה (toggle)
element.classList.toggle("active");

// בדיקה
if (element.classList.contains("active")) {
    console.log("האלמנט פעיל");
}

// החלפת class אחד באחר
element.classList.replace("old", "new");

שינוי Attributes

const link = document.querySelector("a");

// קריאת attribute
console.log(link.getAttribute("href"));

// שינוי/הוספת attribute
link.setAttribute("href", "https://google.com");
link.setAttribute("target", "_blank");

// הסרת attribute
link.removeAttribute("target");

// בדיקה
if (link.hasAttribute("href")) {
    console.log("יש href");
}

תכונות נפוצות

const img = document.querySelector("img");
img.src = "image.jpg";
img.alt = "תיאור התמונה";

const input = document.querySelector("input");
input.value = "ערך חדש";
input.placeholder = "הכנס טקסט";
input.disabled = true;

const checkbox = document.querySelector('input[type="checkbox"]');
checkbox.checked = true;

יצירת אלמנטים חדשים

// יצירת אלמנט
const newDiv = document.createElement("div");
newDiv.textContent = "אני div חדש!";
newDiv.className = "box";
newDiv.id = "newBox";

// הוספה לדף
document.body.appendChild(newDiv);

// הוספה לאלמנט ספציפי
const container = document.querySelector("#container");
container.appendChild(newDiv);

הוספה במיקום ספציפי

const parent = document.querySelector("#parent");
const newElement = document.createElement("li");
newElement.textContent = "פריט חדש";

// בסוף
parent.appendChild(newElement);

// בהתחלה
parent.prepend(newElement);

// לפני אלמנט ספציפי
const reference = parent.querySelector(".specific");
parent.insertBefore(newElement, reference);

// אחרי אלמנט ספציפי
reference.after(newElement);

// לפני אלמנט ספציפי
reference.before(newElement);

הסרת אלמנטים

const element = document.querySelector("#toRemove");

// שיטה 1: remove() (מודרני)
element.remove();

// שיטה 2: דרך ההורה
const parent = document.querySelector("#parent");
parent.removeChild(element);

שכפול אלמנט

const original = document.querySelector("#original");

// שכפול ללא ילדים
const shallowClone = original.cloneNode(false);

// שכפול עם כל הילדים
const deepClone = original.cloneNode(true);

document.body.appendChild(deepClone);

ניווט בעץ ה-DOM

const element = document.querySelector("#element");

// הורה
element.parentElement;
element.parentNode;

// ילדים
element.children;          // HTMLCollection של אלמנטים
element.childNodes;        // NodeList כולל טקסט
element.firstElementChild;
element.lastElementChild;

// אחים
element.nextElementSibling;
element.previousElementSibling;

דוגמה מלאה

HTML

<!DOCTYPE html>
<html>
<head>
    <title>דוגמת DOM</title>
    <style>
        .highlight { background-color: yellow; }
        .hidden { display: none; }
    </style>
</head>
<body>
    <h1 id="title">כותרת</h1>
    <ul id="list">
        <li>פריט 1</li>
        <li>פריט 2</li>
    </ul>
    <button id="addBtn">הוסף פריט</button>
    <button id="toggleBtn">הסתר/הצג רשימה</button>

    <script src="app.js"></script>
</body>
</html>

JavaScript

// בחירת אלמנטים
const title = document.querySelector("#title");
const list = document.querySelector("#list");
const addBtn = document.querySelector("#addBtn");
const toggleBtn = document.querySelector("#toggleBtn");

// שינוי כותרת
title.textContent = "רשימת הפריטים שלי";
title.style.color = "blue";

// הוספת פריט חדש
addBtn.addEventListener("click", () => {
    const newItem = document.createElement("li");
    const itemCount = list.children.length + 1;
    newItem.textContent = `פריט ${itemCount}`;
    list.appendChild(newItem);
});

// הסתרה/הצגה של הרשימה
toggleBtn.addEventListener("click", () => {
    list.classList.toggle("hidden");
});

// הדגשה בלחיצה על פריט
list.addEventListener("click", (e) => {
    if (e.target.tagName === "LI") {
        e.target.classList.toggle("highlight");
    }
});

טיפים חשובים

1. ממתינים שהדף ייטען

<!-- אפשרות 1: script בסוף -->
<body>
    <!-- תוכן -->
    <script src="app.js"></script>
</body>

<!-- אפשרות 2: defer -->
<head>
    <script src="app.js" defer></script>
</head>

<!-- אפשרות 3: DOMContentLoaded -->
<script>
document.addEventListener("DOMContentLoaded", () => {
    // הקוד שלך כאן
});
</script>

2. ביצועים

// ❌ לא יעיל - גורם לreflow בכל איטרציה
for (let i = 0; i < 100; i++) {
    document.body.innerHTML += `<div>${i}</div>`;
}

// ✅ יעיל - שינוי אחד
let html = "";
for (let i = 0; i < 100; i++) {
    html += `<div>${i}</div>`;
}
document.body.innerHTML = html;

// ✅ יעיל יותר - DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
    const div = document.createElement("div");
    div.textContent = i;
    fragment.appendChild(div);
}
document.body.appendChild(fragment);

סיכום

פעולה מתודה
בחירה לפי ID getElementById("id")
בחירה לפי selector querySelector("selector")
בחירת כולם querySelectorAll("selector")
שינוי טקסט element.textContent = "..."
שינוי HTML element.innerHTML = "..."
שינוי סגנון element.style.property = "..."
הוספת class element.classList.add("...")
יצירת אלמנט document.createElement("tag")
הוספה לדף parent.appendChild(element)
הסרה element.remove()

אירועים (Events)

אירועים הם פעולות שקורות בדף - לחיצות, הקלדות, תנועות עכבר ועוד. JavaScript מאפשרת להגיב לאירועים אלה.


מה זה אירוע?

אירוע הוא כל פעולה שקורית בדף: - לחיצת עכבר - הקלדה במקלדת - טעינת הדף - הזזת העכבר - שינוי גודל החלון - ועוד...


הוספת Event Listener

addEventListener (מומלץ!)

const button = document.querySelector("#myButton");

button.addEventListener("click", function() {
    console.log("לחצת על הכפתור!");
});

// עם arrow function
button.addEventListener("click", () => {
    console.log("לחצת על הכפתור!");
});

// עם פונקציה נפרדת
function handleClick() {
    console.log("לחצת על הכפתור!");
}
button.addEventListener("click", handleClick);

שיטות ישנות (פחות מומלצות)

// onclick property
button.onclick = function() {
    console.log("לחצת!");
};

// inline HTML (לא מומלץ!)
// <button onclick="handleClick()">לחץ</button>

סוגי אירועים נפוצים

אירועי עכבר

element.addEventListener("click", handler);      // לחיצה
element.addEventListener("dblclick", handler);   // לחיצה כפולה
element.addEventListener("mouseenter", handler); // עכבר נכנס
element.addEventListener("mouseleave", handler); // עכבר יוצא
element.addEventListener("mousemove", handler);  // עכבר זז
element.addEventListener("mousedown", handler);  // לחצן עכבר נלחץ
element.addEventListener("mouseup", handler);    // לחצן עכבר שוחרר

אירועי מקלדת

document.addEventListener("keydown", handler);   // מקש נלחץ
document.addEventListener("keyup", handler);     // מקש שוחרר
document.addEventListener("keypress", handler);  // מקש נלחץ (deprecated)

אירועי טפסים

input.addEventListener("focus", handler);   // קיבל פוקוס
input.addEventListener("blur", handler);    // איבד פוקוס
input.addEventListener("input", handler);   // ערך השתנה
input.addEventListener("change", handler);  // ערך השתנה (סיום)
form.addEventListener("submit", handler);   // טופס נשלח

אירועי דף

window.addEventListener("load", handler);          // הדף נטען
document.addEventListener("DOMContentLoaded", handler); // DOM מוכן
window.addEventListener("resize", handler);        // גודל השתנה
window.addEventListener("scroll", handler);        // גלילה

Event Object

כל handler מקבל אובייקט event עם מידע על האירוע:

button.addEventListener("click", function(event) {
    console.log(event.type);    // "click"
    console.log(event.target);  // האלמנט שנלחץ
    console.log(event.currentTarget); // האלמנט עם הlistener
});

// קיצור נפוץ
button.addEventListener("click", (e) => {
    console.log(e.target);
});

מידע על עכבר

element.addEventListener("click", (e) => {
    console.log(e.clientX, e.clientY);  // מיקום בחלון
    console.log(e.pageX, e.pageY);      // מיקום בדף
    console.log(e.button);              // איזה כפתור (0=שמאל)
});

מידע על מקלדת

document.addEventListener("keydown", (e) => {
    console.log(e.key);      // "Enter", "a", "ArrowUp"
    console.log(e.code);     // "Enter", "KeyA", "ArrowUp"
    console.log(e.shiftKey); // האם Shift לחוץ
    console.log(e.ctrlKey);  // האם Ctrl לחוץ
    console.log(e.altKey);   // האם Alt לחוץ

    if (e.key === "Enter") {
        console.log("לחצת Enter!");
    }
});

preventDefault - מניעת ברירת מחדל

// מניעת שליחת טופס
form.addEventListener("submit", (e) => {
    e.preventDefault();  // הדף לא יתרענן
    console.log("הטופס נקלט!");
    // עיבוד הנתונים...
});

// מניעת פתיחת קישור
link.addEventListener("click", (e) => {
    e.preventDefault();
    console.log("מנעתי מעבר לקישור");
});

stopPropagation - עצירת התפשטות

אירועים "מבעבעים" למעלה בעץ ה-DOM:

/*
<div id="outer">
    <div id="inner">
        <button id="btn">לחץ</button>
    </div>
</div>
*/

const outer = document.querySelector("#outer");
const inner = document.querySelector("#inner");
const btn = document.querySelector("#btn");

outer.addEventListener("click", () => console.log("outer"));
inner.addEventListener("click", () => console.log("inner"));
btn.addEventListener("click", (e) => {
    console.log("button");
    e.stopPropagation();  // עוצר את ההתפשטות
});

// לחיצה על הכפתור תדפיס רק "button"
// בלי stopPropagation היה מדפיס: "button", "inner", "outer"

Event Delegation

טכניקה יעילה - הוספת listener אחד להורה במקום לכל ילד:

/*
<ul id="list">
    <li>פריט 1</li>
    <li>פריט 2</li>
    <li>פריט 3</li>
</ul>
*/

const list = document.querySelector("#list");

// ❌ לא יעיל - listener לכל li
document.querySelectorAll("li").forEach(li => {
    li.addEventListener("click", () => {
        console.log(li.textContent);
    });
});

// ✅ יעיל - listener אחד על הרשימה
list.addEventListener("click", (e) => {
    if (e.target.tagName === "LI") {
        console.log(e.target.textContent);
    }
});

// יתרון: עובד גם על פריטים שיתווספו בעתיד!

הסרת Event Listener

function handleClick() {
    console.log("לחצת!");
}

// הוספה
button.addEventListener("click", handleClick);

// הסרה
button.removeEventListener("click", handleClick);

// ❌ לא עובד עם פונקציה אנונימית
button.addEventListener("click", () => console.log("שלום"));
button.removeEventListener("click", () => console.log("שלום")); // לא אותה פונקציה!

once - הרצה פעם אחת

button.addEventListener("click", () => {
    console.log("זה יקרה רק פעם אחת!");
}, { once: true });

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

Toggle Button

const toggleBtn = document.querySelector("#toggle");
const content = document.querySelector("#content");

toggleBtn.addEventListener("click", () => {
    content.classList.toggle("hidden");
    toggleBtn.textContent = content.classList.contains("hidden") 
        ? "הצג" 
        : "הסתר";
});

Form Validation

const form = document.querySelector("#form");
const emailInput = document.querySelector("#email");
const errorMsg = document.querySelector("#error");

form.addEventListener("submit", (e) => {
    e.preventDefault();

    const email = emailInput.value;

    if (!email.includes("@")) {
        errorMsg.textContent = "אימייל לא תקין";
        emailInput.classList.add("invalid");
    } else {
        errorMsg.textContent = "";
        emailInput.classList.remove("invalid");
        console.log("הטופס נשלח!");
    }
});

Character Counter

const textarea = document.querySelector("#message");
const counter = document.querySelector("#counter");
const maxLength = 100;

textarea.addEventListener("input", () => {
    const remaining = maxLength - textarea.value.length;
    counter.textContent = `נותרו ${remaining} תווים`;

    if (remaining < 10) {
        counter.style.color = "red";
    } else {
        counter.style.color = "black";
    }
});

Keyboard Shortcuts

document.addEventListener("keydown", (e) => {
    // Ctrl+S
    if (e.ctrlKey && e.key === "s") {
        e.preventDefault();
        console.log("שומר...");
    }

    // Escape
    if (e.key === "Escape") {
        console.log("סוגר...");
    }
});

Drag & Drop (בסיסי)

const draggable = document.querySelector("#draggable");
const dropzone = document.querySelector("#dropzone");

draggable.addEventListener("dragstart", (e) => {
    e.dataTransfer.setData("text/plain", draggable.id);
});

dropzone.addEventListener("dragover", (e) => {
    e.preventDefault();  // מאפשר drop
});

dropzone.addEventListener("drop", (e) => {
    e.preventDefault();
    const id = e.dataTransfer.getData("text/plain");
    const element = document.getElementById(id);
    dropzone.appendChild(element);
});

דוגמה מלאה - Todo List

HTML

<div id="app">
    <h1>רשימת משימות</h1>
    <form id="todoForm">
        <input type="text" id="todoInput" placeholder="משימה חדשה...">
        <button type="submit">הוסף</button>
    </form>
    <ul id="todoList"></ul>
</div>

JavaScript

const form = document.querySelector("#todoForm");
const input = document.querySelector("#todoInput");
const list = document.querySelector("#todoList");

// הוספת משימה
form.addEventListener("submit", (e) => {
    e.preventDefault();

    const text = input.value.trim();
    if (!text) return;

    const li = document.createElement("li");
    li.innerHTML = `
        <span>${text}</span>
        <button class="delete">מחק</button>
    `;

    list.appendChild(li);
    input.value = "";
    input.focus();
});

// מחיקה והשלמה (delegation)
list.addEventListener("click", (e) => {
    const li = e.target.closest("li");

    if (e.target.classList.contains("delete")) {
        li.remove();
    } else if (e.target.tagName === "SPAN") {
        li.classList.toggle("completed");
    }
});

סיכום

אירוע מתי קורה
click לחיצת עכבר
dblclick לחיצה כפולה
keydown מקש נלחץ
keyup מקש שוחרר
submit טופס נשלח
input ערך השתנה
focus אלמנט קיבל פוקוס
blur אלמנט איבד פוקוס
mouseenter עכבר נכנס
mouseleave עכבר יצא
load הדף נטען
scroll גלילה

כללי אצבע: - השתמשו ב-addEventListener - השתמשו ב-Event Delegation לביצועים טובים - השתמשו ב-preventDefault() לשלוט בהתנהגות - זכרו שאירועים "מבעבעים" למעלה

תכנות אסינכרוני (Asynchronous Programming)

JavaScript היא שפה single-threaded, אבל יכולה לבצע פעולות ברקע בזכות מנגנון האסינכרוניות.


למה צריך קוד אסינכרוני?

פעולות מסוימות לוקחות זמן: - קריאות לשרת (API) - קריאת קבצים - טיימרים - אנימציות

בלי אסינכרוניות, הדף היה "נתקע" עד שהפעולה מסתיימת.

// ❌ קוד סינכרוני שנתקע
console.log("התחלה");
// ...המתנה של 3 שניות...
console.log("סוף");

// ✅ קוד אסינכרוני - הדף ממשיך לעבוד
console.log("התחלה");
setTimeout(() => {
    console.log("אחרי 3 שניות");
}, 3000);
console.log("ממשיך מיד");

setTimeout ו-setInterval

setTimeout - הרצה אחרי זמן

console.log("התחלה");

setTimeout(() => {
    console.log("עברו 2 שניות");
}, 2000);  // 2000 מילישניות = 2 שניות

console.log("ממשיך");
// פלט: "התחלה", "ממשיך", "עברו 2 שניות"

ביטול setTimeout

const timerId = setTimeout(() => {
    console.log("זה לא ירוץ");
}, 5000);

// ביטול
clearTimeout(timerId);

setInterval - הרצה חוזרת

let count = 0;
const intervalId = setInterval(() => {
    count++;
    console.log(`פעם ${count}`);

    if (count >= 5) {
        clearInterval(intervalId);  // עצירה
    }
}, 1000);  // כל שנייה

Callbacks

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

function fetchData(callback) {
    setTimeout(() => {
        const data = { name: "דן", age: 25 };
        callback(data);  // קריאה ל-callback עם הנתונים
    }, 2000);
}

fetchData((result) => {
    console.log("קיבלתי:", result);
});

Callback Hell (הבעיה)

// ❌ קשה לקריאה ותחזוקה
getData((data) => {
    processData(data, (processed) => {
        saveData(processed, (saved) => {
            notifyUser(saved, (notification) => {
                console.log("סיום!");
            });
        });
    });
});

Promises

Promise הוא אובייקט שמייצג ערך עתידי - הוא יכול להצליח (resolve) או להיכשל (reject).

יצירת Promise

const myPromise = new Promise((resolve, reject) => {
    // פעולה אסינכרונית
    setTimeout(() => {
        const success = true;

        if (success) {
            resolve("הצלחה!");  // מחזיר ערך
        } else {
            reject("נכשל!");    // מחזיר שגיאה
        }
    }, 2000);
});

שימוש ב-Promise

myPromise
    .then((result) => {
        console.log("הצלחה:", result);
    })
    .catch((error) => {
        console.log("שגיאה:", error);
    })
    .finally(() => {
        console.log("תמיד רץ - הצלחה או כישלון");
    });

שרשור Promises

fetchUser(userId)
    .then((user) => {
        console.log("משתמש:", user.name);
        return fetchPosts(user.id);
    })
    .then((posts) => {
        console.log("פוסטים:", posts.length);
        return fetchComments(posts[0].id);
    })
    .then((comments) => {
        console.log("תגובות:", comments.length);
    })
    .catch((error) => {
        console.error("שגיאה בשרשרת:", error);
    });

async/await

תחביר מודרני ונקי יותר לעבודה עם Promises:

פונקציה async

async function getData() {
    return "נתונים";  // מחזיר Promise אוטומטית
}

getData().then(result => console.log(result));  // "נתונים"

await - המתנה ל-Promise

async function fetchData() {
    console.log("מתחיל...");

    const response = await fetch("https://api.example.com/data");
    const data = await response.json();

    console.log("קיבלתי:", data);
    return data;
}

fetchData();

טיפול בשגיאות

async function fetchData() {
    try {
        const response = await fetch("https://api.example.com/data");

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        return data;

    } catch (error) {
        console.error("שגיאה:", error.message);
        return null;
    }
}

השוואה: Promises vs async/await

// עם Promises
function getUser() {
    return fetch("/api/user")
        .then(response => response.json())
        .then(user => {
            console.log(user);
            return user;
        })
        .catch(error => console.error(error));
}

// עם async/await (נקי יותר)
async function getUser() {
    try {
        const response = await fetch("/api/user");
        const user = await response.json();
        console.log(user);
        return user;
    } catch (error) {
        console.error(error);
    }
}

Promise.all

הרצת מספר Promises במקביל:

async function fetchAllData() {
    try {
        // כל הבקשות יוצאות במקביל
        const [users, posts, comments] = await Promise.all([
            fetch("/api/users").then(r => r.json()),
            fetch("/api/posts").then(r => r.json()),
            fetch("/api/comments").then(r => r.json())
        ]);

        console.log("משתמשים:", users.length);
        console.log("פוסטים:", posts.length);
        console.log("תגובות:", comments.length);

    } catch (error) {
        // אם אחת נכשלת - הכל נכשל
        console.error("שגיאה:", error);
    }
}

Promise.race

מחזיר את התוצאה הראשונה (הצלחה או כישלון):

async function fetchWithTimeout(url, timeout = 5000) {
    const timeoutPromise = new Promise((_, reject) => {
        setTimeout(() => reject(new Error("Timeout!")), timeout);
    });

    const fetchPromise = fetch(url);

    return Promise.race([fetchPromise, timeoutPromise]);
}

Promise.allSettled

ממתין לכולם, גם אם חלק נכשלים:

const promises = [
    fetch("/api/users"),
    fetch("/api/posts"),
    fetch("/api/bad-url")  // יכשל
];

const results = await Promise.allSettled(promises);

results.forEach((result, index) => {
    if (result.status === "fulfilled") {
        console.log(`#${index} הצליח:`, result.value);
    } else {
        console.log(`#${index} נכשל:`, result.reason);
    }
});

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

טעינת נתונים עם Loading

async function loadUsers() {
    const loadingEl = document.querySelector("#loading");
    const listEl = document.querySelector("#userList");

    loadingEl.style.display = "block";

    try {
        const response = await fetch("/api/users");
        const users = await response.json();

        listEl.innerHTML = users
            .map(user => `<li>${user.name}</li>`)
            .join("");

    } catch (error) {
        listEl.innerHTML = "<li>שגיאה בטעינה</li>";

    } finally {
        loadingEl.style.display = "none";
    }
}

Debounce - עיכוב הרצה

function debounce(func, delay) {
    let timeoutId;

    return function(...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

// שימוש - חיפוש שמחכה שהמשתמש יפסיק להקליד
const searchInput = document.querySelector("#search");
const search = debounce((query) => {
    console.log("מחפש:", query);
    // קריאה לAPI
}, 300);

searchInput.addEventListener("input", (e) => {
    search(e.target.value);
});

Retry - ניסיון חוזר

async function fetchWithRetry(url, retries = 3) {
    for (let i = 0; i < retries; i++) {
        try {
            const response = await fetch(url);
            if (response.ok) {
                return await response.json();
            }
        } catch (error) {
            console.log(`ניסיון ${i + 1} נכשל`);

            if (i === retries - 1) {
                throw error;
            }

            // המתנה לפני ניסיון נוסף
            await new Promise(r => setTimeout(r, 1000));
        }
    }
}

Event Loop (איך זה עובד)

┌───────────────────────────┐
│         Call Stack        │  ← JavaScript רץ כאן
└───────────────────────────┘
            ↓
┌───────────────────────────┐
│       Web APIs            │  ← setTimeout, fetch, etc.
│   (מנוהל ע"י הדפדפן)       │
└───────────────────────────┘
            ↓
┌───────────────────────────┐
│     Callback Queue        │  ← callbacks ממתינים
└───────────────────────────┘
            ↓
┌───────────────────────────┐
│       Event Loop          │  ← מעביר לStack כשפנוי
└───────────────────────────┘
console.log("1");

setTimeout(() => {
    console.log("2");
}, 0);

Promise.resolve().then(() => {
    console.log("3");
});

console.log("4");

// פלט: 1, 4, 3, 2
// (Microtasks/Promises קודמים ל-setTimeout)

סיכום

מושג תיאור
Callback פונקציה שתקרא בסיום פעולה
Promise אובייקט שמייצג ערך עתידי
async מגדיר פונקציה אסינכרונית
await ממתין ל-Promise
try/catch טיפול בשגיאות
Promise.all הרצה במקביל, כולם חייבים להצליח
Promise.race הראשון שמסתיים
Promise.allSettled כולם, גם עם כישלונות

כללי אצבע: - העדיפו async/await על פני .then() - תמיד טפלו בשגיאות עם try/catch - השתמשו ב-Promise.all לבקשות מקביליות - הימנעו מ-callback hell

קריאות שרת (Fetch API)

Fetch API מאפשרת לתקשר עם שרתים - לקבל ולשלוח נתונים דרך HTTP.


מה זה API?

API (Application Programming Interface) הוא ממשק שמאפשר לתוכנות לתקשר זו עם זו. בהקשר של ווב, מדובר בנקודות קצה (endpoints) בשרת שאפשר לפנות אליהן.

┌─────────────────┐    HTTP Request    ┌─────────────────┐
│                 │  ──────────────▶   │                 │
│    Frontend     │                    │    Backend      │
│   (JavaScript)  │  ◀──────────────   │    (Server)     │
│                 │    HTTP Response   │                 │
└─────────────────┘                    └─────────────────┘

HTTP Methods (שיטות)

Method שימוש דוגמה
GET קבלת נתונים לקבל רשימת משתמשים
POST יצירת נתון חדש יצירת משתמש חדש
PUT עדכון כל הנתון עדכון כל פרטי המשתמש
PATCH עדכון חלקי עדכון שם בלבד
DELETE מחיקה מחיקת משתמש

fetch בסיסי (GET)

// בקשת GET פשוטה
fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error("שגיאה:", error);
    });

עם async/await

async function getUsers() {
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        const users = await response.json();
        console.log(users);
    } catch (error) {
        console.error("שגיאה:", error);
    }
}

getUsers();

Response Object

האובייקט שחוזר מ-fetch מכיל מידע על התשובה:

async function checkResponse() {
    const response = await fetch("/api/users");

    console.log(response.status);      // 200, 404, 500...
    console.log(response.ok);          // true אם status 200-299
    console.log(response.statusText);  // "OK", "Not Found"...
    console.log(response.headers);     // Headers object

    // קריאת הגוף (אפשר רק פעם אחת!)
    const data = await response.json();
}

בדיקת תקינות התשובה

async function fetchData(url) {
    const response = await fetch(url);

    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    return await response.json();
}

שליחת נתונים (POST)

async function createUser(user) {
    const response = await fetch("https://api.example.com/users", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(user)
    });

    const newUser = await response.json();
    return newUser;
}

// שימוש
const user = await createUser({
    name: "דן",
    email: "[email protected]"
});
console.log("נוצר:", user);

עדכון נתונים (PUT/PATCH)

PUT - החלפה מלאה

async function updateUser(id, userData) {
    const response = await fetch(`https://api.example.com/users/${id}`, {
        method: "PUT",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(userData)
    });

    return response.json();
}

PATCH - עדכון חלקי

async function updateUserEmail(id, email) {
    const response = await fetch(`https://api.example.com/users/${id}`, {
        method: "PATCH",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({ email })
    });

    return response.json();
}

מחיקה (DELETE)

async function deleteUser(id) {
    const response = await fetch(`https://api.example.com/users/${id}`, {
        method: "DELETE"
    });

    if (response.ok) {
        console.log("המשתמש נמחק");
    }
}

Headers

async function fetchWithAuth() {
    const response = await fetch("/api/protected-data", {
        headers: {
            "Content-Type": "application/json",
            "Authorization": "Bearer YOUR_TOKEN_HERE",
            "Accept-Language": "he"
        }
    });

    return response.json();
}

טיפול בשגיאות

async function fetchWithErrorHandling(url) {
    try {
        const response = await fetch(url);

        // בדיקת סטטוס
        if (!response.ok) {
            if (response.status === 404) {
                throw new Error("לא נמצא");
            } else if (response.status === 401) {
                throw new Error("לא מורשה");
            } else if (response.status >= 500) {
                throw new Error("שגיאת שרת");
            } else {
                throw new Error(`שגיאה: ${response.status}`);
            }
        }

        return await response.json();

    } catch (error) {
        // שגיאת רשת (אין חיבור)
        if (error.name === "TypeError") {
            console.error("בעיית חיבור לרשת");
        } else {
            console.error(error.message);
        }
        throw error;
    }
}

Query Parameters

// דרך 1: ידנית
const url = "https://api.example.com/users?page=1&limit=10";

// דרך 2: URLSearchParams
const params = new URLSearchParams({
    page: 1,
    limit: 10,
    sort: "name"
});
const url2 = `https://api.example.com/users?${params}`;
// "https://api.example.com/users?page=1&limit=10&sort=name"

// דרך 3: URL object
const url3 = new URL("https://api.example.com/users");
url3.searchParams.append("page", 1);
url3.searchParams.append("limit", 10);

AbortController - ביטול בקשה

const controller = new AbortController();

// ביטול אחרי 5 שניות
setTimeout(() => controller.abort(), 5000);

try {
    const response = await fetch("/api/data", {
        signal: controller.signal
    });
    const data = await response.json();
} catch (error) {
    if (error.name === "AbortError") {
        console.log("הבקשה בוטלה");
    } else {
        console.error("שגיאה:", error);
    }
}

FormData - שליחת טפסים

// מטופס קיים
const form = document.querySelector("#myForm");
const formData = new FormData(form);

await fetch("/api/submit", {
    method: "POST",
    body: formData  // לא צריך Content-Type header!
});

// ידנית
const data = new FormData();
data.append("name", "דן");
data.append("file", fileInput.files[0]);

await fetch("/api/upload", {
    method: "POST",
    body: data
});

דוגמה מלאה - CRUD Application

const API_URL = "https://jsonplaceholder.typicode.com";

// READ - קבלת כל המשתמשים
async function getUsers() {
    const response = await fetch(`${API_URL}/users`);
    return response.json();
}

// READ - קבלת משתמש ספציפי
async function getUser(id) {
    const response = await fetch(`${API_URL}/users/${id}`);
    if (!response.ok) throw new Error("משתמש לא נמצא");
    return response.json();
}

// CREATE - יצירת משתמש
async function createUser(userData) {
    const response = await fetch(`${API_URL}/users`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(userData)
    });
    return response.json();
}

// UPDATE - עדכון משתמש
async function updateUser(id, userData) {
    const response = await fetch(`${API_URL}/users/${id}`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(userData)
    });
    return response.json();
}

// DELETE - מחיקת משתמש
async function deleteUser(id) {
    const response = await fetch(`${API_URL}/users/${id}`, {
        method: "DELETE"
    });
    return response.ok;
}

// שימוש
async function main() {
    try {
        // קבלת כל המשתמשים
        const users = await getUsers();
        console.log("משתמשים:", users.length);

        // קבלת משתמש ספציפי
        const user = await getUser(1);
        console.log("משתמש:", user.name);

        // יצירה
        const newUser = await createUser({
            name: "דן ישראלי",
            email: "[email protected]"
        });
        console.log("נוצר:", newUser);

    } catch (error) {
        console.error("שגיאה:", error.message);
    }
}

main();

טעינת נתונים עם UI

async function loadUsersToPage() {
    const container = document.querySelector("#users");
    const loading = document.querySelector("#loading");
    const error = document.querySelector("#error");

    // הצגת טעינה
    loading.style.display = "block";
    error.style.display = "none";
    container.innerHTML = "";

    try {
        const response = await fetch("/api/users");

        if (!response.ok) {
            throw new Error("שגיאה בטעינת המשתמשים");
        }

        const users = await response.json();

        // בניית ה-HTML
        container.innerHTML = users.map(user => `
            <div class="user-card">
                <h3>${user.name}</h3>
                <p>${user.email}</p>
            </div>
        `).join("");

    } catch (err) {
        error.textContent = err.message;
        error.style.display = "block";

    } finally {
        loading.style.display = "none";
    }
}

// טעינה בעליית הדף
document.addEventListener("DOMContentLoaded", loadUsersToPage);

JSON

עבודה עם JSON

// המרה למחרוזת JSON
const obj = { name: "דן", age: 25 };
const jsonString = JSON.stringify(obj);
console.log(jsonString);  // '{"name":"דן","age":25}'

// המרה מ-JSON לאובייקט
const parsed = JSON.parse(jsonString);
console.log(parsed.name);  // "דן"

// JSON יפה (לקריאה)
const pretty = JSON.stringify(obj, null, 2);

XMLHttpRequest (לידע כללי)

הדרך הישנה לבקשות HTTP (לפני fetch):

// ❌ הדרך הישנה
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/users");
xhr.onload = function() {
    if (xhr.status === 200) {
        const data = JSON.parse(xhr.responseText);
        console.log(data);
    }
};
xhr.onerror = function() {
    console.error("שגיאה");
};
xhr.send();

// ✅ fetch מודרני
const response = await fetch("/api/users");
const data = await response.json();

סיכום

פעולה קוד
GET fetch(url)
POST fetch(url, { method: "POST", body: ... })
PUT fetch(url, { method: "PUT", body: ... })
DELETE fetch(url, { method: "DELETE" })
קריאת JSON response.json()
בדיקת תקינות response.ok או response.status
שליחת JSON body: JSON.stringify(data)
Headers headers: { "Content-Type": "application/json" }

כללי אצבע: - תמיד בדקו response.ok לפני עיבוד התשובה - השתמשו ב-try/catch לטיפול בשגיאות - השתמשו ב-async/await לקוד נקי - אל תשכחו את Content-Type header בשליחת JSON

שיטות עבודה מומלצות (Best Practices)

אוסף של טיפים וכללים לכתיבת קוד JavaScript נקי, קריא ותחזיקתי.


מוסכמות שמות (Naming Conventions)

משתנים ופונקציות - camelCase

// ✅ טוב
let userName = "דן";
let totalAmount = 100;
function calculateTotal() { }
function getUserData() { }

// ❌ לא מומלץ
let user_name = "דן";
let TOTALAMOUNT = 100;

קבועים - SCREAMING_SNAKE_CASE

const MAX_USERS = 100;
const API_BASE_URL = "https://api.example.com";
const DEFAULT_TIMEOUT = 5000;

Classes ו-Constructors - PascalCase

class UserProfile { }
class ShoppingCart { }
function Person(name) {
    this.name = name;
}

Boolean - שאלות

// ✅ ברור שזה boolean
let isActive = true;
let hasPermission = false;
let canEdit = true;
let shouldUpdate = false;

// ❌ לא ברור
let active = true;
let permission = false;

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

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

// ❌ פונקציה שעושה יותר מדי
function processUser(user) {
    // אימות
    // עדכון DB
    // שליחת אימייל
    // עדכון לוג
}

// ✅ פונקציות קטנות וממוקדות
function validateUser(user) { }
function saveUser(user) { }
function sendWelcomeEmail(user) { }
function logUserCreation(user) { }

שמות תיאוריים

// ❌ לא ברור
function process(d) { }
function doStuff(x, y) { }

// ✅ ברור מה הפונקציה עושה
function calculateTotalPrice(items) { }
function formatDateForDisplay(date) { }
function validateEmailAddress(email) { }

ערכי ברירת מחדל

// ✅ ברירות מחדל מונעות undefined
function createUser(name, role = "user", active = true) {
    return { name, role, active };
}

// ✅ עם destructuring
function greet({ name = "אורח", greeting = "שלום" } = {}) {
    return `${greeting} ${name}!`;
}

עבודה עם משתנים

const כברירת מחדל

// ✅ השתמשו ב-const אם הערך לא משתנה
const API_URL = "https://api.example.com";
const config = { debug: true };

// השתמשו ב-let רק כשצריך לשנות
let count = 0;
count++;

הימנעו מ-var

// ❌ var - בעיות scope
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// ידפיס: 3, 3, 3

// ✅ let - מתנהג כמצופה
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// ידפיס: 0, 1, 2

Destructuring

// ❌ ארוך
const name = user.name;
const age = user.age;
const city = user.address.city;

// ✅ קצר וקריא
const { name, age, address: { city } } = user;

// עם מערכים
const [first, second, ...rest] = items;

השוואות ותנאים

השתמשו ב-=== ו-!==

// ❌ השוואה רופפת
if (value == "5") { }

// ✅ השוואה מדויקת
if (value === "5") { }
if (value === 5) { }

התנאים הקצרים

// ❌ מסורבל
if (array.length > 0) {
    return true;
} else {
    return false;
}

// ✅ פשוט
return array.length > 0;

// Optional chaining
const city = user?.address?.city;

// Nullish coalescing
const name = user.name ?? "אנונימי";

Early Return

// ❌ קשה לקריאה
function processUser(user) {
    if (user) {
        if (user.active) {
            if (user.role === "admin") {
                // הרבה קוד
            }
        }
    }
}

// ✅ קל לקריאה
function processUser(user) {
    if (!user) return;
    if (!user.active) return;
    if (user.role !== "admin") return;

    // הקוד הראשי
}

עבודה עם מערכים

שימוש במתודות פונקציונליות

// ❌ לולאה מסורבלת
const doubled = [];
for (let i = 0; i < numbers.length; i++) {
    doubled.push(numbers[i] * 2);
}

// ✅ קצר וקריא
const doubled = numbers.map(n => n * 2);

// סינון
const adults = users.filter(u => u.age >= 18);

// מציאה
const admin = users.find(u => u.role === "admin");

// בדיקה
const hasAdmin = users.some(u => u.role === "admin");

Spread ו-Destructuring

// ✅ העתקה
const copy = [...originalArray];
const merged = [...array1, ...array2];

// הוספה לתחילה/סוף
const withFirst = [newItem, ...array];
const withLast = [...array, newItem];

עבודה עם אובייקטים

Spread לעדכון

// ✅ עדכון אימטבילי
const updatedUser = {
    ...user,
    name: "שם חדש",
    age: user.age + 1
};

// מיזוג
const merged = { ...defaults, ...userSettings };

Shorthand Properties

const name = "דן";
const age = 25;

// ❌ חזרה
const user = { name: name, age: age };

// ✅ קיצור
const user = { name, age };

טיפול בשגיאות

תמיד תפסו שגיאות בקוד אסינכרוני

// ✅ try/catch עם async
async function fetchData() {
    try {
        const response = await fetch("/api/data");
        return await response.json();
    } catch (error) {
        console.error("שגיאה:", error);
        return null;
    }
}

// ✅ .catch עם promises
fetch("/api/data")
    .then(res => res.json())
    .catch(error => {
        console.error("שגיאה:", error);
    });

שגיאות ספציפיות

// ✅ מידע ברור בשגיאה
throw new Error(`משתמש ${userId} לא נמצא`);

// ✅ בדיקות מפורטות
if (!response.ok) {
    if (response.status === 404) {
        throw new Error("לא נמצא");
    } else if (response.status === 401) {
        throw new Error("לא מורשה");
    }
    throw new Error(`שגיאה: ${response.status}`);
}

הערות ותיעוד

הערות שמסבירות למה, לא מה

// ❌ מה - מובן מהקוד
// מגדיל את count ב-1
count++;

// ✅ למה - לא מובן מהקוד
// מוסיף 1 כי ה-API מחזיר 0-indexed
displayedPage = apiPage + 1;

// ✅ הסבר של לוגיקה מורכבת
// משתמשים ב-debounce כי ה-API מגביל ל-100 בקשות בדקה
const debouncedSearch = debounce(search, 300);

JSDoc לפונקציות מורכבות

/**
 * מחשב את המחיר הכולל כולל הנחה
 * @param {number} price - מחיר הבסיס
 * @param {number} quantity - כמות
 * @param {number} [discount=0] - אחוז הנחה (אופציונלי)
 * @returns {number} המחיר הסופי
 */
function calculateTotal(price, quantity, discount = 0) {
    const subtotal = price * quantity;
    return subtotal - (subtotal * discount / 100);
}

Debugging

console מתקדם

// טבלה
console.table([{ name: "דן", age: 25 }, { name: "דנה", age: 30 }]);

// קיבוץ
console.group("פרטי משתמש");
console.log("שם:", user.name);
console.log("גיל:", user.age);
console.groupEnd();

// זמן ביצוע
console.time("פעולה");
// ... קוד ...
console.timeEnd("פעולה");

// תנאי
console.assert(value > 0, "הערך חייב להיות חיובי");

Breakpoints

// עצירה בקוד
debugger;

// או בDevTools - לחיצה על מספר השורה

ביצועים

הימנעו מפעולות DOM מיותרות

// ❌ עדכון DOM בכל איטרציה
for (let item of items) {
    container.innerHTML += `<div>${item}</div>`;
}

// ✅ בניית HTML ועדכון אחד
const html = items.map(item => `<div>${item}</div>`).join("");
container.innerHTML = html;

Debounce ו-Throttle

// Debounce - ממתין שהמשתמש יפסיק להקליד
const debouncedSearch = debounce(search, 300);
input.addEventListener("input", debouncedSearch);

// Throttle - מבצע מקסימום פעם ב-X זמן
const throttledScroll = throttle(handleScroll, 100);
window.addEventListener("scroll", throttledScroll);

אבטחה

הימנעו מ-innerHTML עם קלט משתמש

// ❌ מסוכן - XSS
element.innerHTML = userInput;

// ✅ בטוח
element.textContent = userInput;

// ✅ אם חייבים HTML - נקו קודם
element.innerHTML = DOMPurify.sanitize(userInput);

אל תשמרו מידע רגיש ב-Client

// ❌ לעולם לא!
const PRIVATE_KEY = "secret123";
localStorage.setItem("password", password);

// ✅ רק בשרת
// הטוקנים נשמרים בצורה מאובטחת (httpOnly cookies)

סיכום

נושא כלל
משתנים const כברירת מחדל
השוואות תמיד ===
פונקציות קטנות וממוקדות
שגיאות תמיד try/catch באסינכרוני
מערכים map, filter, find
DOM מינימום עדכונים
אבטחה textContent ולא innerHTML

עקרונות כלליים: - קוד קריא עדיף על קוד "חכם" - DRY - Don't Repeat Yourself - KISS - Keep It Simple, Stupid - עדכנו קוד ישן כשנוגעים בו - כתבו קוד שאתם תרצו לתחזק בעוד שנה

ביטויים רגולריים (Regular Expressions)

מה זה Regex?

ביטויים רגולריים (Regular Expressions או בקיצור Regex) הם תבניות המשמשות לחיפוש, התאמה ומניפולציה של טקסט. הם כלי רב-עוצמה לעבודה עם מחרוזות.

┌─────────────────────────────────────────────────┐
│                    Regex                        │
│  ┌──────────────┐    ┌──────────────────────┐   │
│  │  תבנית חיפוש  │ → │  התאמה במחרוזת       │   │
│  │   /hello/    │    │  "hello world"       │   │
│  └──────────────┘    └──────────────────────┘   │
└─────────────────────────────────────────────────┘

יצירת Regex ב-JavaScript

שתי דרכים ליצירת Regex

// 1. Literal notation - הדרך הנפוצה
const regex1 = /hello/;

// 2. Constructor - שימושי כשהתבנית דינמית
const regex2 = new RegExp('hello');

// עם דגלים (flags)
const regex3 = /hello/gi;
const regex4 = new RegExp('hello', 'gi');

דגלים (Flags)

דגלים משנים את התנהגות החיפוש:

דגל שם משמעות
g global מצא את כל ההתאמות, לא רק הראשונה
i case-insensitive התעלם מהבדלי אותיות גדולות/קטנות
m multiline התייחס לכל שורה כמחרוזת נפרדת
s dotAll נקודה תתאים גם לשורה חדשה
u unicode תמיכה מלאה ב-Unicode
// חיפוש ללא רגישות לאותיות
const regex = /hello/i;
console.log(regex.test('HELLO'));  // true
console.log(regex.test('Hello'));  // true

// מציאת כל ההתאמות
const str = 'cat cat cat';
const matches = str.match(/cat/g);
console.log(matches);  // ['cat', 'cat', 'cat']

תווים מיוחדים

Meta Characters - תווי מטא

תו משמעות דוגמה
. כל תו בודד (חוץ משורה חדשה) a.c מתאים ל-abc, aXc
\d ספרה (0-9) \d\d מתאים ל-42
\D לא ספרה \D מתאים ל-a, !
\w תו מילה (a-z, A-Z, 0-9, _) \w+ מתאים ל-hello_123
\W לא תו מילה \W מתאים ל-@,
\s רווח לבן (space, tab, newline) \s+ מתאים לרווחים
\S לא רווח לבן \S+ מתאים למילה
\b גבול מילה \bcat\b מתאים ל-cat אך לא ל-category
\n שורה חדשה
\t טאב
// חיפוש ספרות
const phone = '054-1234567';
console.log(phone.match(/\d+/g));  // ['054', '1234567']

// חיפוש מילים
const text = 'Hello World 123';
console.log(text.match(/\w+/g));  // ['Hello', 'World', '123']

כימות (Quantifiers)

כמה פעמים התו יופיע

כימות משמעות דוגמה
* 0 או יותר ab*cac, abc, abbc
+ 1 או יותר ab+cabc, abbc (לא ac)
? 0 או 1 colou?rcolor, colour
{n} בדיוק n פעמים a{3}aaa
{n,} n או יותר a{2,}aa, aaa, aaaa...
{n,m} בין n ל-m פעמים a{2,4}aa, aaa, aaaa
// מספר טלפון ישראלי
const phoneRegex = /^0\d{1,2}-?\d{7}$/;
console.log(phoneRegex.test('054-1234567'));  // true
console.log(phoneRegex.test('02-1234567'));   // true
console.log(phoneRegex.test('0541234567'));   // true

// כתובת דוא"ל פשוטה
const emailRegex = /\w+@\w+\.\w+/;
console.log(emailRegex.test('[email protected]'));  // true

קבוצות וטווחים

Character Classes - מחלקות תווים

// טווח של אותיות
const regex1 = /[a-z]/;     // אות קטנה אחת
const regex2 = /[A-Z]/;     // אות גדולה אחת
const regex3 = /[0-9]/;     // ספרה (כמו \d)
const regex4 = /[a-zA-Z]/;  // כל אות

// תווים ספציפיים
const vowels = /[aeiou]/gi;
const text = 'Hello World';
console.log(text.match(vowels));  // ['e', 'o', 'o']

// שלילה עם ^
const notDigit = /[^0-9]/;  // כל תו שהוא לא ספרה
console.log('a1b2'.match(/[^0-9]/g));  // ['a', 'b']

Groups - קבוצות

// קבוצות לכידה (Capturing Groups)
const regex = /(\d{2})-(\d{2})-(\d{4})/;
const date = '25-12-2024';
const match = date.match(regex);

console.log(match[0]);  // '25-12-2024' (כל ההתאמה)
console.log(match[1]);  // '25' (קבוצה ראשונה)
console.log(match[2]);  // '12' (קבוצה שנייה)
console.log(match[3]);  // '2024' (קבוצה שלישית)

// קבוצות עם שמות (Named Groups)
const namedRegex = /(?<day>\d{2})-(?<month>\d{2})-(?<year>\d{4})/;
const namedMatch = date.match(namedRegex);

console.log(namedMatch.groups.day);    // '25'
console.log(namedMatch.groups.month);  // '12'
console.log(namedMatch.groups.year);   // '2024'

עוגנים (Anchors)

עוגנים מציינים מיקום במחרוזת:

עוגן משמעות
^ תחילת המחרוזת
$ סוף המחרוזת
\b גבול מילה
\B לא גבול מילה
// מתחיל עם "Hello"
const startsWithHello = /^Hello/;
console.log(startsWithHello.test('Hello World'));  // true
console.log(startsWithHello.test('Say Hello'));    // false

// מסתיים עם ספרות
const endsWithNumber = /\d+$/;
console.log(endsWithNumber.test('version 2'));    // true
console.log(endsWithNumber.test('2 items'));      // false

// מילה שלמה בלבד
const wholeWord = /\bcat\b/;
console.log(wholeWord.test('cat'));        // true
console.log(wholeWord.test('category'));   // false
console.log(wholeWord.test('a cat here')); // true

מתודות של Regex

test() - בדיקת התאמה

const regex = /hello/i;

// מחזיר true או false
console.log(regex.test('Hello World'));  // true
console.log(regex.test('Goodbye'));      // false

exec() - ביצוע חיפוש מפורט

const regex = /(\w+)@(\w+)\.(\w+)/;
const email = '[email protected]';

const result = regex.exec(email);
console.log(result[0]);  // '[email protected]'
console.log(result[1]);  // 'user'
console.log(result[2]);  // 'example'
console.log(result[3]);  // 'com'
console.log(result.index);  // 0 (מיקום ההתאמה)

מתודות מחרוזת עם Regex

match() - מציאת התאמות

const text = 'The rain in Spain stays mainly in the plain';

// התאמה ראשונה בלבד
console.log(text.match(/ain/));
// ['ain', index: 5, input: '...']

// כל ההתאמות עם g flag
console.log(text.match(/ain/g));
// ['ain', 'ain', 'ain', 'ain']

matchAll() - כל ההתאמות עם פרטים

const text = 'cat bat rat';
const regex = /[cbr]at/g;

for (const match of text.matchAll(regex)) {
    console.log(`נמצא: ${match[0]} במיקום ${match.index}`);
}
// נמצא: cat במיקום 0
// נמצא: bat במיקום 4
// נמצא: rat במיקום 8

replace() - החלפת טקסט

// החלפה פשוטה
const text = 'Hello World';
console.log(text.replace(/World/, 'JavaScript'));
// 'Hello JavaScript'

// החלפת כל ההתאמות
const text2 = 'cat cat cat';
console.log(text2.replace(/cat/g, 'dog'));
// 'dog dog dog'

// שימוש בקבוצות
const name = 'John Smith';
console.log(name.replace(/(\w+) (\w+)/, '$2, $1'));
// 'Smith, John'

// פונקציית החלפה
const prices = 'Items cost $5 and $10';
const converted = prices.replace(/\$(\d+)/g, (match, amount) => {
    return `₪${amount * 3.5}`;
});
console.log(converted);
// 'Items cost ₪17.5 and ₪35'

replaceAll() - החלפת כל ההתאמות

const text = 'a-b-c-d';
console.log(text.replaceAll('-', '_'));
// 'a_b_c_d'

// עם regex (חייב דגל g)
console.log(text.replaceAll(/-/g, '_'));
// 'a_b_c_d'

search() - חיפוש אינדקס

const text = 'Hello World';

console.log(text.search(/World/));  // 6
console.log(text.search(/xyz/));    // -1 (לא נמצא)

split() - פיצול מחרוזת

// פיצול לפי תבנית
const text = 'apple, banana; cherry  orange';
const fruits = text.split(/[,;\s]+/);
console.log(fruits);
// ['apple', 'banana', 'cherry', 'orange']

// פיצול עם שמירת המפריד
const text2 = 'one1two2three3';
const parts = text2.split(/(\d)/);
console.log(parts);
// ['one', '1', 'two', '2', 'three', '3', '']

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

ולידציה של נתונים

// ולידציית אימייל
function isValidEmail(email) {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(email);
}

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

// ולידציית מספר טלפון ישראלי
function isValidPhoneIL(phone) {
    const regex = /^0(5[0-9]|[2-4]|[7-9])\d{7}$/;
    return regex.test(phone.replace(/-/g, ''));
}

console.log(isValidPhoneIL('054-1234567'));  // true
console.log(isValidPhoneIL('02-1234567'));   // true

// ולידציית סיסמה
function isStrongPassword(password) {
    // לפחות 8 תווים, אות גדולה, אות קטנה, ספרה
    const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
    return regex.test(password);
}

console.log(isStrongPassword('MyPass123'));  // true
console.log(isStrongPassword('weak'));       // false

// ולידציית ת.ז. ישראלית (9 ספרות)
function isValidIsraeliID(id) {
    const regex = /^\d{9}$/;
    return regex.test(id);
}

חילוץ מידע

// חילוץ כתובות URL
function extractURLs(text) {
    const regex = /https?:\/\/[^\s]+/g;
    return text.match(regex) || [];
}

const text = 'Visit https://example.com or http://test.org';
console.log(extractURLs(text));
// ['https://example.com', 'http://test.org']

// חילוץ האשטאגים
function extractHashtags(text) {
    const regex = /#\w+/g;
    return text.match(regex) || [];
}

const tweet = 'Love #JavaScript and #coding! #webdev';
console.log(extractHashtags(tweet));
// ['#JavaScript', '#coding', '#webdev']

// חילוץ מספרים
function extractNumbers(text) {
    const regex = /-?\d+\.?\d*/g;
    return text.match(regex)?.map(Number) || [];
}

console.log(extractNumbers('Price: 25.99, Discount: -5'));
// [25.99, -5]

ניקוי וטרנספורמציה

// הסרת HTML tags
function stripHTML(html) {
    return html.replace(/<[^>]*>/g, '');
}

console.log(stripHTML('<p>Hello <b>World</b></p>'));
// 'Hello World'

// המרה ל-camelCase
function toCamelCase(str) {
    return str.replace(/[-_\s]+(.)/g, (_, char) => char.toUpperCase());
}

console.log(toCamelCase('hello-world'));      // 'helloWorld'
console.log(toCamelCase('my_variable_name')); // 'myVariableName'

// הוספת פסיקים למספרים גדולים
function formatNumber(num) {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

console.log(formatNumber(1234567));  // '1,234,567'

// ניקוי רווחים מיותרים
function cleanWhitespace(text) {
    return text.replace(/\s+/g, ' ').trim();
}

console.log(cleanWhitespace('  Hello    World  '));
// 'Hello World'

Lookahead ו-Lookbehind

Lookahead - הסתכלות קדימה

// Positive Lookahead: (?=...)
// מצא "foo" שאחריו יש "bar"
const regex1 = /foo(?=bar)/;
console.log(regex1.test('foobar'));  // true
console.log(regex1.test('foobaz'));  // false

// Negative Lookahead: (?!...)
// מצא "foo" שאחריו אין "bar"
const regex2 = /foo(?!bar)/;
console.log(regex2.test('foobaz'));  // true
console.log(regex2.test('foobar'));  // false

Lookbehind - הסתכלות אחורה

// Positive Lookbehind: (?<=...)
// מצא מספר שלפניו יש $
const regex3 = /(?<=\$)\d+/;
console.log('$100'.match(regex3));  // ['100']

// Negative Lookbehind: (?<!...)
// מצא מספר שלפניו אין $
const regex4 = /(?<!\$)\d+/;
console.log('100'.match(regex4));   // ['100']
console.log('$100'.match(regex4));  // ['00'] (כי 1 בא אחרי $)

טעויות נפוצות

1. שכחת דגל g

// לא נכון - מחליף רק את הראשון
const text = 'cat cat cat';
console.log(text.replace(/cat/, 'dog'));  // 'dog cat cat'

// נכון - מחליף את כולם
console.log(text.replace(/cat/g, 'dog')); // 'dog dog dog'

2. לא בריחה מתווים מיוחדים

// לא נכון - הנקודה זה wildcard
const regex1 = /example.com/;
console.log(regex1.test('exampleXcom'));  // true (לא נכון!)

// נכון - בריחה עם \
const regex2 = /example\.com/;
console.log(regex2.test('exampleXcom'));  // false
console.log(regex2.test('example.com'));  // true

3. Greedy vs Lazy

// Greedy (ברירת מחדל) - לוקח הכי הרבה
const text = '<div>Hello</div><div>World</div>';
console.log(text.match(/<div>.*<\/div>/)[0]);
// '<div>Hello</div><div>World</div>' (הכל!)

// Lazy (עם ?) - לוקח הכי מעט
console.log(text.match(/<div>.*?<\/div>/)[0]);
// '<div>Hello</div>' (רק הראשון)

סיכום

  • Regex הם כלי עוצמתי לעבודה עם טקסט
  • דגלים כמו g, i, m משנים התנהגות
  • תווי מטא כמו \d, \w, \s מייצגים קבוצות תווים
  • כימות כמו *, +, {n,m} קובעים כמה פעמים
  • קבוצות () מאפשרות לכידה והתייחסות
  • מתודות כמו test(), match(), replace() מפעילות regex

💡 טיפ: השתמשו בכלים אונליין כמו regex101.com לבדיקה ולימוד של ביטויים רגולריים!