שיטות עבודה מומלצות

אוסף של טיפים וכללים לכתיבת קוד 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 - עדכנו קוד ישן כשנוגעים בו - כתבו קוד שאתם תרצו לתחזק בעוד שנה

בדקו את עצמכם

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

  1. מה עדיף לרוב הערכים?

    1. let
    2. var
    3. אין הבדל
    4. const
    הצגת התשובה

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

  2. למה להימנע ממשתנים גלובליים?

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

    תשובה ג. מודולים ופונקציות עם scope מקומי שומרים על קוד צפוי.