ITSkillsCenter
تطوير الويب

تعلّم JavaScript من الصفر: أساسيات البرمجة التفاعلية للويب

7 min de lecture

مقدمة في JavaScript

تُعد JavaScript لغة البرمجة الأكثر استخداماً في العالم وهي اللغة الوحيدة التي تعمل في متصفحات الويب بشكل أصلي. منذ إنشائها عام 1995 بواسطة Brendan Eich في 10 أيام فقط، تطورت JavaScript لتصبح لغة متعددة الأغراض تُستخدم في تطوير الواجهات الأمامية والخلفية وتطبيقات الموبايل وحتى تطبيقات سطح المكتب. في هذا الدليل الشامل، سنتعلم أساسيات JavaScript الحديثة بأمثلة عملية تفاعلية تؤهلك لبناء تطبيقات ويب كاملة.

تُستخدم JavaScript اليوم في أكثر من 98% من مواقع الويب، وتدعمها أطر عمل قوية مثل React و Vue و Angular للواجهات الأمامية، و Node.js للواجهات الخلفية. إتقان أساسيات JavaScript هو الخطوة الأولى والأهم في مسيرتك كمطور ويب.

المتغيرات وأنواع البيانات

تعريف المتغيرات

في JavaScript الحديث (ES6+)، نستخدم let و const بدلاً من var القديم. الفرق الأساسي أن const للقيم الثابتة التي لا تتغير، وlet للقيم المتغيرة:

// const - قيمة ثابتة لا يمكن إعادة تعيينها
const PI = 3.14159;
const APP_NAME = "تطبيق المتجر";
const API_URL = "https://api.example.com";

// let - قيمة متغيرة يمكن تحديثها
let userName = "أحمد";
let score = 0;
let isLoggedIn = false;

// تحديث قيمة let
score = 100;       // ✅ مسموح
userName = "محمد"; // ✅ مسموح

// محاولة تغيير const
// PI = 3.14;      // ❌ TypeError: Assignment to constant

// ⚠️ لا تستخدم var - لها مشاكل في النطاق (scope)
// var oldWay = "تجنب هذا";

أنواع البيانات الأساسية

// الأنواع البدائية (Primitive Types)
let text = "مرحباً بالعالم";       // String - نص
let number = 42;                    // Number - رقم
let decimal = 3.14;                 // Number - عشري
let isActive = true;                // Boolean - منطقي
let nothing = null;                 // Null - فارغ عمداً
let notDefined = undefined;         // Undefined - غير معرّف
let uniqueId = Symbol("id");        // Symbol - معرّف فريد
let bigNum = 9007199254740991n;     // BigInt - أرقام كبيرة

// فحص نوع البيانات
console.log(typeof text);           // "string"
console.log(typeof number);         // "number"
console.log(typeof isActive);       // "boolean"
console.log(typeof nothing);        // "object" (خطأ تاريخي)
console.log(typeof notDefined);     // "undefined"

// تحويل الأنواع
let strNum = "42";
let realNum = Number(strNum);       // 42
let realNum2 = parseInt("42px");    // 42
let str = String(42);               // "42"
let bool = Boolean(1);              // true
let bool2 = Boolean("");            // false

المصفوفات (Arrays)

المصفوفات هي هياكل بيانات مرتبة تخزّن مجموعة من العناصر. توفر JavaScript أساليب قوية جداً للتعامل مع المصفوفات:

// إنشاء مصفوفة
const fruits = ["تفاح", "موز", "برتقال", "فراولة"];
const numbers = [1, 2, 3, 4, 5];
const mixed = ["نص", 42, true, null];

// الوصول للعناصر
console.log(fruits[0]);              // "تفاح"
console.log(fruits[fruits.length-1]); // "فراولة"

// إضافة وحذف العناصر
fruits.push("عنب");                  // إضافة في النهاية
fruits.unshift("مانجو");             // إضافة في البداية
fruits.pop();                        // حذف من النهاية
fruits.shift();                      // حذف من البداية
fruits.splice(1, 1);                 // حذف عنصر بالفهرس

// أساليب البحث
const index = fruits.indexOf("موز"); // موقع العنصر
const found = fruits.find(f => f.length > 4); // أول عنصر يطابق
const exists = fruits.includes("تفاح"); // هل موجود؟

// أساليب التحويل المهمة
// map - تحويل كل عنصر
const prices = [10, 20, 30];
const withTax = prices.map(p => p * 1.2);
// [12, 24, 36]

// filter - تصفية العناصر
const expensive = prices.filter(p => p > 15);
// [20, 30]

// reduce - تجميع القيم
const total = prices.reduce((sum, p) => sum + p, 0);
// 60

// forEach - التكرار
fruits.forEach((fruit, i) => {
  console.log(i + ": " + fruit);
});

// sort - الترتيب
const sorted = [...numbers].sort((a, b) => b - a);
// ترتيب تنازلي: [5, 4, 3, 2, 1]

الكائنات (Objects)

// إنشاء كائن
const user = {
  name: "سارة",
  age: 28,
  email: "sara@example.com",
  skills: ["JavaScript", "React", "Node.js"],
  address: {
    city: "الدار البيضاء",
    country: "المغرب"
  },
  // دالة داخل كائن (method)
  greet() {
    return "مرحباً، أنا " + this.name;
  }
};

// الوصول للخصائص
console.log(user.name);              // "سارة"
console.log(user["email"]);          // نمط الأقواس
console.log(user.address.city);      // "الدار البيضاء"
console.log(user.greet());           // "مرحباً، أنا سارة"

// التفكيك (Destructuring)
const { name, age, skills } = user;
console.log(name);                   // "سارة"

// التفكيك المتداخل
const { address: { city } } = user;
console.log(city);                   // "الدار البيضاء"

// دمج الكائنات
const defaults = { theme: "dark", language: "ar" };
const settings = { ...defaults, language: "fr" };
// { theme: "dark", language: "fr" }

// Object methods
const keys = Object.keys(user);     // مفاتيح الكائن
const values = Object.values(user);  // قيم الكائن
const entries = Object.entries(user); // أزواج [مفتاح، قيمة]

الدوال (Functions)

// تعريف دالة تقليدية
function calculateArea(width, height) {
  return width * height;
}

// دالة سهمية (Arrow Function) - الطريقة الحديثة
const calculateArea2 = (width, height) => width * height;

// معاملات افتراضية
const greet = (name = "زائر", time = "صباحاً") => {
  return "مرحباً " + name + "! " + time;
};
greet();            // "مرحباً زائر! صباحاً"
greet("أحمد");      // "مرحباً أحمد! صباحاً"

// Rest parameters - جمع معاملات متعددة
const sum = (...numbers) => {
  return numbers.reduce((total, n) => total + n, 0);
};
sum(1, 2, 3, 4);   // 10

// دالة تُرجع دالة (Closure)
const createCounter = (start = 0) => {
  let count = start;
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count
  };
};
const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.decrement(); // 11

// دوال Higher-Order
const applyDiscount = (discount) => (price) => price * (1 - discount);
const tenPercent = applyDiscount(0.1);
tenPercent(100);    // 90

التعامل مع DOM

يسمح Document Object Model لـ JavaScript بالتفاعل مع عناصر صفحة HTML وتعديلها ديناميكياً:

// اختيار العناصر
const title = document.getElementById("main-title");
const buttons = document.querySelectorAll(".btn");
const firstCard = document.querySelector(".card:first-child");

// تعديل المحتوى والأنماط
title.textContent = "عنوان جديد";
title.innerHTML = "عنوان جديد";
title.style.color = "#2563eb";
title.style.fontSize = "2rem";

// إضافة وإزالة الفئات
title.classList.add("active", "highlighted");
title.classList.remove("hidden");
title.classList.toggle("dark-mode");

// إنشاء عناصر جديدة
const newCard = document.createElement("div");
newCard.className = "card";
newCard.innerHTML = "

بطاقة جديدة

محتوى البطاقة

"; document.querySelector(".cards-container").appendChild(newCard); // الأحداث (Events) const btn = document.querySelector("#submit-btn"); btn.addEventListener("click", (event) => { event.preventDefault(); console.log("تم النقر على الزر!"); }); // أحداث لوحة المفاتيح document.addEventListener("keydown", (e) => { if (e.key === "Escape") { closeModal(); } }); // تفويض الأحداث (Event Delegation) document.querySelector(".list").addEventListener("click", (e) => { if (e.target.matches(".delete-btn")) { e.target.closest("li").remove(); } });

البرمجة غير المتزامنة (Async)

معظم عمليات JavaScript الحقيقية غير متزامنة مثل جلب البيانات من خادم أو قراءة ملف. إليك الطرق المختلفة للتعامل معها:

// Promises - الوعود
const fetchData = (url) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url) resolve({ data: "بيانات من " + url });
      else reject(new Error("رابط غير صالح"));
    }, 1000);
  });
};

fetchData("/api/users")
  .then(result => console.log(result))
  .catch(error => console.error(error));

// Async/Await - الطريقة الحديثة والأوضح
const loadUserData = async () => {
  try {
    const response = await fetch("/api/users");
    if (!response.ok) throw new Error("فشل في الجلب");
    const users = await response.json();
    console.log("المستخدمون:", users);
    return users;
  } catch (error) {
    console.error("خطأ:", error.message);
  }
};

// تنفيذ عمليات متعددة بالتوازي
const loadDashboard = async () => {
  try {
    const [users, products, orders] = await Promise.all([
      fetch("/api/users").then(r => r.json()),
      fetch("/api/products").then(r => r.json()),
      fetch("/api/orders").then(r => r.json())
    ]);
    console.log("تم تحميل جميع البيانات");
  } catch (error) {
    console.error("فشل تحميل البيانات:", error);
  }
};

الفئات والبرمجة الكائنية

// تعريف فئة (Class)
class Product {
  constructor(name, price, category) {
    this.name = name;
    this.price = price;
    this.category = category;
    this.createdAt = new Date();
  }

  // method
  getFormattedPrice() {
    return this.price.toFixed(2) + " د.م";
  }

  applyDiscount(percent) {
    this.price *= (1 - percent / 100);
    return this;
  }

  toString() {
    return this.name + " - " + this.getFormattedPrice();
  }

  // Static method
  static compare(a, b) {
    return a.price - b.price;
  }
}

// الوراثة (Inheritance)
class DigitalProduct extends Product {
  constructor(name, price, category, downloadUrl) {
    super(name, price, category);
    this.downloadUrl = downloadUrl;
    this.type = "digital";
  }

  getDownloadLink() {
    return "تحميل: " + this.downloadUrl;
  }
}

// الاستخدام
const laptop = new Product("حاسوب محمول", 5000, "إلكترونيات");
console.log(laptop.getFormattedPrice()); // "5000.00 د.م"
laptop.applyDiscount(10);
console.log(laptop.getFormattedPrice()); // "4500.00 د.م"

const ebook = new DigitalProduct("كتاب JavaScript", 50, "كتب", "/downloads/js.pdf");
console.log(ebook.getDownloadLink());

التخزين المحلي (Local Storage)

// حفظ واسترجاع البيانات
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme"); // "dark"

// حفظ كائنات (يجب تحويلها لنص JSON)
const cart = [
  { name: "هاتف", price: 3000, qty: 1 },
  { name: "سماعات", price: 200, qty: 2 }
];
localStorage.setItem("cart", JSON.stringify(cart));

// استرجاع الكائنات
const savedCart = JSON.parse(localStorage.getItem("cart"));
console.log(savedCart[0].name); // "هاتف"

// حذف عنصر أو مسح الكل
localStorage.removeItem("theme");
localStorage.clear();

// مثال عملي: حفظ إعدادات المستخدم
const saveSettings = (settings) => {
  localStorage.setItem("userSettings", JSON.stringify(settings));
};
const loadSettings = () => {
  const saved = localStorage.getItem("userSettings");
  return saved ? JSON.parse(saved) : { theme: "light", lang: "ar" };
};

مشروع تطبيقي: قائمة مهام تفاعلية

// تطبيق قائمة المهام الكامل
class TodoApp {
  constructor() {
    this.todos = JSON.parse(localStorage.getItem("todos")) || [];
    this.container = document.querySelector("#todo-app");
    this.init();
  }

  init() {
    this.render();
    document.querySelector("#add-form")
      .addEventListener("submit", (e) => {
        e.preventDefault();
        const input = document.querySelector("#todo-input");
        if (input.value.trim()) {
          this.addTodo(input.value.trim());
          input.value = "";
        }
      });
  }

  addTodo(text) {
    this.todos.push({
      id: Date.now(),
      text: text,
      completed: false,
      createdAt: new Date().toISOString()
    });
    this.save();
    this.render();
  }

  toggleTodo(id) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) todo.completed = !todo.completed;
    this.save();
    this.render();
  }

  deleteTodo(id) {
    this.todos = this.todos.filter(t => t.id !== id);
    this.save();
    this.render();
  }

  save() {
    localStorage.setItem("todos", JSON.stringify(this.todos));
  }

  render() {
    const html = this.todos.map(todo =>
      '
  • ' + '' + todo.text + '' + '' + '
  • ' ).join(""); this.container.innerHTML = "
      " + html + "
    "; } } const app = new TodoApp();

    معالجة الأخطاء (Error Handling)

    معالجة الأخطاء بشكل صحيح أمر ضروري لبناء تطبيقات موثوقة ومستقرة. توفر JavaScript عدة آليات للتعامل مع الأخطاء المتوقعة وغير المتوقعة:

    // Try-Catch للتعامل مع الأخطاء
    try {
      const data = JSON.parse(invalidJson);
      console.log(data);
    } catch (error) {
      console.error("خطأ في تحليل JSON:", error.message);
    } finally {
      console.log("يتم تنفيذه دائماً");
    }
    
    // إنشاء أخطاء مخصصة
    class ValidationError extends Error {
      constructor(field, message) {
        super(message);
        this.name = "ValidationError";
        this.field = field;
      }
    }
    
    const validateEmail = (email) => {
      if (!email) throw new ValidationError("email", "البريد مطلوب");
      if (!email.includes("@")) throw new ValidationError("email", "بريد غير صالح");
      return true;
    };
    
    try {
      validateEmail("");
    } catch (error) {
      if (error instanceof ValidationError) {
        console.log("خطأ في الحقل:", error.field);
        console.log("الرسالة:", error.message);
      }
    }
    
    // معالجة أخطاء Promises
    const fetchWithRetry = async (url, retries = 3) => {
      for (let i = 0; i < retries; i++) {
        try {
          const response = await fetch(url);
          if (!response.ok) throw new Error("HTTP " + response.status);
          return await response.json();
        } catch (error) {
          if (i === retries - 1) throw error;
          console.log("محاولة " + (i + 2) + " من " + retries);
          await new Promise(r => setTimeout(r, 1000 * (i + 1)));
        }
      }
    };

    الوحدات (Modules)

    تسمح وحدات ES6 بتقسيم الكود إلى ملفات منفصلة قابلة لإعادة الاستخدام مما يحسّن تنظيم المشروع وصيانته:

    // utils/math.js - تصدير الدوال
    export const add = (a, b) => a + b;
    export const multiply = (a, b) => a * b;
    
    export default class Calculator {
      constructor() { this.result = 0; }
      add(n) { this.result += n; return this; }
      subtract(n) { this.result -= n; return this; }
      getResult() { return this.result; }
    }
    
    // app.js - استيراد الدوال
    import Calculator, { add, multiply } from "./utils/math.js";
    
    console.log(add(5, 3));          // 8
    console.log(multiply(4, 6));     // 24
    
    const calc = new Calculator();
    calc.add(10).subtract(3).add(5);
    console.log(calc.getResult());   // 12
    
    // استيراد ديناميكي (Dynamic Import)
    const loadChart = async () => {
      const { default: Chart } = await import("./chart.js");
      new Chart("canvas-id").render();
    };

    ميزات ES6+ الحديثة

    // Template Literals - قوالب النصوص
    const name = "أحمد";
    const greeting = 'مرحباً ' + name + '! اليوم هو ' + new Date().toLocaleDateString("ar");
    
    // Optional Chaining - التسلسل الاختياري
    const user = { profile: { address: { city: "الرباط" } } };
    const city = user?.profile?.address?.city; // "الرباط"
    const zip = user?.profile?.address?.zip;   // undefined (بدون خطأ)
    
    // Nullish Coalescing - دمج القيم الفارغة
    const port = undefined;
    const serverPort = port ?? 3000;           // 3000
    const count = 0;
    const result = count ?? 10;                // 0 (لأن 0 ليس null/undefined)
    
    // Spread و Rest مع المصفوفات والكائنات
    const arr1 = [1, 2, 3];
    const arr2 = [4, 5, 6];
    const combined = [...arr1, ...arr2];       // [1,2,3,4,5,6]
    
    const obj1 = { a: 1, b: 2 };
    const obj2 = { b: 3, c: 4 };
    const merged = { ...obj1, ...obj2 };       // { a:1, b:3, c:4 }
    
    // Map و Set
    const uniqueVisitors = new Set();
    uniqueVisitors.add("user1");
    uniqueVisitors.add("user2");
    uniqueVisitors.add("user1");               // لن يُضاف (مكرر)
    console.log(uniqueVisitors.size);          // 2
    
    const cache = new Map();
    cache.set("users", [{name: "أحمد"}]);
    cache.set("ttl", 300);
    console.log(cache.get("users"));
    console.log(cache.has("ttl"));             // true

    نصائح وأخطاء شائعة

    • استخدم === بدلاً من ==: المقارنة الصارمة تمنع التحويل التلقائي للأنواع الذي يسبب أخطاء خفية مثل "0" == false التي تعطي true
    • تجنب المتغيرات العامة: استخدم const و let داخل الكتل والدوال بدلاً من إنشاء متغيرات عامة تلوّث النطاق العام
    • تعامل مع الأخطاء دائماً: لا تترك Promises بدون catch أو كود بدون try-catch عند التعامل مع بيانات خارجية
    • استخدم الدوال النقية: الدوال التي لا تعدّل بيانات خارجية وتُرجع دائماً نفس النتيجة لنفس المدخلات أسهل في الاختبار والصيانة
    • تعلّم Debugging: استخدم console.log و console.table و debugger وأدوات المطور في المتصفح لتتبع الأخطاء

    ملخص المهارات المكتسبة

    • فهم المتغيرات وأنواع البيانات الأساسية والمتقدمة في JavaScript
    • إتقان المصفوفات وأساليبها الحديثة: map, filter, reduce, find
    • بناء واستخدام الكائنات مع التفكيك ودمج الكائنات
    • كتابة دوال حديثة باستخدام Arrow Functions و Closures
    • التعامل مع DOM لبناء واجهات تفاعلية ديناميكية
    • إتقان البرمجة غير المتزامنة مع Promises و Async/Await
    • استخدام الفئات والوراثة في البرمجة الكائنية
    • التخزين المحلي لحفظ بيانات المستخدم
    • بناء تطبيق تفاعلي كامل من الصفر

    الخطوة التالية

    بعد إتقان أساسيات JavaScript، انتقل إلى تعلم React.js أو Vue.js لبناء واجهات مستخدم معقدة وقابلة للتوسع. استكشف Node.js لتطوير الواجهات الخلفية باستخدام نفس اللغة. تعلم TypeScript لإضافة أنواع بيانات ثابتة وتحسين جودة الكود في المشاريع الكبيرة.

    Besoin d'un site web ?

    Confiez-nous la Création de Votre Site Web

    Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

    À partir de 350.000 FCFA
    Parlons de Votre Projet
    Publicité