مقدمة عن البرمجة الكائنية في الجافاسكربت

لو أنت لسة بتبدأ في عالم البرمجة وبتحاول تفهم JavaScript بشكل أعمق، هقولك سر صغير: البرمجة الكائنية (OOP) هي اللي هتخلي كودك يبقى منظم، سهل التعديل، ومش هيبقى زي الفوضى اللي بنشوفها في الكودات البسيطة.

تخيل إنك بتصمم لعبة فيديو، مش هتكتب كل حركة لكل شخصية لوحدها؛ هتقسمها لكائنات زي اللاعب، الأعداء، والعوائق، وكل واحد يعمل دوره. JavaScript، اللي كانت في الأول لغة إجرائية أكتر، من ES6 بقت تدعم OOP بشكل رسمي وممتع.

في المقالة دي، هنغوص أعمق في البرمجة الكائنية في JavaScript للمبتدئين، مع أمثلة عملية كتيرة، خطوة بخطوة، عشان تفهمها وتطبقها في مشاريعك اليومية. لو عايز تبدأ رحلتك في تعلم OOP في JavaScript، خليك معايا، وهتخرج من هنا محترف! إيه هي البرمجة الكائنية (OOP) بالضبط، ولماذا تهمك كمبتدئ؟

البرمجة الكائنية، أو Object-Oriented Programming (OOP)، هي طريقة تفكير في البرمجة مستوحاة من الحياة الواقعية. زي ما بنقسم العالم لأشياء (كائنات) زي السيارات، الناس، والحيوانات، كل واحدة ليها خصائص (properties) وتصرفات (methods). في OOP، بنبني الكود من كلاسات (Classes) اللي هي زي القوالب، ومنها بننشئ كائنات (Objects).


ليه OOP مهمة في JavaScript؟

عشان JavaScript بقت لغة أساسية للويب، والتطبيقات الكبيرة زي React أو Node.js بتعتمد عليها. بدون OOP، كودك هيبقى صعب الصيانة، خاصة لو الفريق كبير. الركائز الأساسية لـ OOP في JavaScript هي أربعة:

  • التغليف (Encapsulation): تخفي التفاصيل الداخلية زي ما بتحمي فلوسك في جيبك.
  • الوراثة (Inheritance): الكود الجديد يورث من القديم، عشان توفر وقت.
  • التعددية (Polymorphism): نفس الدالة تشتغل بطرق مختلفة حسب الكائن.
  • التجريد (Abstraction): تركز على اللي محتاجه بس، وتتجاهل التعقيدات.

لو أنت جديد في OOP JavaScript للمبتدئين، متقلقش؛ هنشرح كل ركيزة مع أمثلة، وهنقارنها بالطريقة الإجرائية عشان تشوف الفرق.

الفرق بين OOP و البرمجة الإجرائية (Procedural) في JavaScript في البرمجة الإجرائية، بتكتب خطوات متسلسلة زي وصفة طبخ: "خد الدجاج، قليه، أضف التوابل".

بس في OOP، بتقسمها لكائنات: "الدجاج ليه خصائص زي الوزن، ودالة قلي()". مثال بسيط: إجرائي (بدون OOP):

function cookChicken(weight, spice) {
  console.log(`قلي دجاج وزن ${weight} كجم مع ${spice}`);
}
cookChicken(2, "فلفل");

معا الـ OOP

class Chicken {
  constructor(weight) {
    this.weight = weight;
  }
  cook(spice) {
    console.log(`قلي دجاج وزن ${this.weight} كجم مع ${spice}`);
  }
}
const myChicken = new Chicken(2);
myChicken.cook("فلفل");

شايف الفرق؟ OOP أكثر تنظيماً ومرونة!


ازاي نبدأ مع الكلاسات (Classes) في JavaScript؟ أمثلة عملية

قبل ES6، كنا بنستخدم الدوال البنائية (Constructor Functions)، بس الكلاسات دلوقتي أسهل زي اللي بيشرب شاي. الكلاس هو القالب، والـ constructor هو اللي بيبني الكائن.

مثال أول: سيارة بسيطة

class Car {
  constructor(name, color, year) {
    this.name = name;
    this.color = color;
    this.year = year;
  }

  start() {
    console.log(`${this.year} ${this.name} بدأت تشتغل! اللون: ${this.color}`);
  }

  getAge() {
    const currentYear = new Date().getFullYear();
    return currentYear - this.year;
  }
}

const myCar = new Car("تويوتا", "أحمر", 2020);
myCar.start(); // هيطبع: 2020 تويوتا بدأت تشتغل! اللون: أحمر
console.log(`عمر السيارة: ${myCar.getAge()} سنة`); // 5 سنة (افتراضياً)

مثال ثاني: قائمة مهام (To-Do List) – مثال حقيقي لمبتدئين

تخيل إنك بتعمل تطبيق To-Do. كل مهمة هي كائن:

class Task {
  constructor(title, description, completed = false) {
    this.title = title;
    this.description = description;
    this.completed = completed;
    this.id = Math.random().toString(36).substr(2, 9); // ID عشوائي
  }

  toggleComplete() {
    this.completed = !this.completed;
    console.log(
      `${this.title} ${this.completed ? "تم إنجازها!" : "مش مكتملة"} `
    );
  }

  display() {
    console.log(
      `المهمة: ${this.title} - ${this.description} (${
        this.completed ? "مكتملة" : "معلقة"
      })`
    );
  }
}

const task1 = new Task("تعلم JavaScript", "اقرأ عن OOP");
task1.display();
task1.toggleComplete(); // هيطبع: تعلم JavaScript تم إنجازها!

ده مثال عملي على كلاسات في JavaScript، وهتقدر تستخدمه في مشروع حقيقي زي تطبيق ويب.


الوراثة (Inheritance): ازاي الكود يورث ؟

الوراثة هي اللي بتخلي OOP قوية؛ الكلاس الطفل (child) ياخد كل حاجة من الأب (parent) ويضيف جديد. استخدم extends و super.

مثال أول: سيارة سباق (من السابق، بس مع إضافات)

class RaceCar extends Car {
  constructor(name, color, year, maxSpeed, driver) {
    super(name, color, year); // ورث الخصائص الأساسية
    this.maxSpeed = maxSpeed;
    this.driver = driver;
  }

  race() {
    console.log(
      `${this.driver} بيسابق بـ ${this.name} بسرعة ${this.maxSpeed} كم/س!`
    );
  }

  start() {
    super.start();
    console.log("صوت المحرك زي الرعد! يلا نسابق!");
  }
}

const myRaceCar = new RaceCar("فيراري", "أصفر", 2023, 350, "حمدي");
myRaceCar.start();
myRaceCar.race();

مثال ثاني: حيوانات في حديقة حيوانات – مثال ممتع

class Animal {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  eat() {
    console.log(`${this.name} بياكل!`);
  }

  sleep() {
    console.log(`${this.name} نايم.`);
  }
}

class Dog extends Animal {
  constructor(name, age, breed) {
    super(name, age);
    this.breed = breed;
  }

  bark() {
    console.log(`${this.name} بينبح: ووف ووف!`);
  }

  eat() {
    // Override
    super.eat();
    console.log(${this.breed} بيحب العظام.`);
  }
}

const myDog = new Dog("كريم", 3, "جولدن ريتريفر");
myDog.eat(); // هيطبع: كريم بياكل! وجولدن ريتريفر بيحب العظام.
myDog.bark();

هنا، الوراثة في OOP JavaScript بتوفر كود متكرر، ومثالية لمشاريع زي ألعاب أو تطبيقات تعليمية.


التغليف (Encapsulation): حماية البيانات زي الخزنة السرية

التغليف يحمي البيانات من التغييرات العشوائية. في JS، استخدم # للخاص (private) أو getters/setters.

مثال أول: حساب بنكي (من السابق، بس مع إضافات)

class BankAccount {
  #balance = 0; // خاص تماماً
  #accountNumber;

  constructor(initialBalance, accountNumber) {
    this.#balance = initialBalance;
    this.#accountNumber = accountNumber;
  }

  get balance() {
    return this.#balance;
  }

  get accountNumber() {
    return this.#accountNumber;
  }

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
      console.log(`تم إيداع ${amount} جنيه في الحساب ${this.#accountNumber}`);
    } else {
      console.log("المبلغ لازم يكون إيجابي يا فنان!");
    }
  }

  withdraw(amount) {
    if (amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
      console.log(`تم سحب ${amount} جنيه من الحساب ${this.#accountNumber}`);
    } else {
      console.log("الرصيد مش كفاية أو المبلغ غلط!");
    }
  }
}

const myAccount = new BankAccount(1000, "12345");
myAccount.deposit(500);
console.log(`الرصيد الحالي: ${myAccount.balance} جنيه`); // 1500
myAccount.withdraw(200);

مثال ثاني: لاعب في لعبة – حماية الصحة

class Player {
  #health = 100;
  #name;

  constructor(name) {
    this.#name = name;
  }

  get health() {
    return this.#health;
  }

  get name() {
    return this.#name;
  }

  takeDamage(damage) {
    if (damage > 0 && this.#health > 0) {
      this.#health = Math.max(0, this.#health - damage);
      console.log(
        `${this.#name} خد ضرر ${damage}! الصحة المتبقية: ${this.#health}`
      );
    }
  }

  heal(amount) {
    if (amount > 0) {
      this.#health = Math.min(100, this.#health + amount);
      console.log(`${this.#name} تعافى ${amount} نقاط!`);
    }
  }
}

const hero = new Player("أحمد");
hero.takeDamage(30);
hero.heal(20);
console.log(`${hero.name} صحته: ${hero.health}`);

ده يوضح التغليف في JavaScript، وهيحميك في تطبيقات زي الألعاب أو الشات بوتس.


التعددية (Polymorphism): مرونة زي اللي بيغير رأيه حسب الظروف!

التعددية تخلي الدوال تتكيف مع الكائن. في JS، بتحصل مع override في الوراثة.

مثال: أشكال هندسية – حساب المساحة

class Shape {
  constructor(name) {
    this.name = name;
  }

  area() {
    return 0; // افتراضي
  }
}

class Circle extends Shape {
  constructor(name, radius) {
    super(name);
    this.radius = radius;
  }

  area() {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle extends Shape {
  constructor(name, width, height) {
    super(name);
    this.width = width;
    this.height = height;
  }

  area() {
    return this.width * this.height;
  }
}

const shapes = [new Circle("دائرة", 5), new Rectangle("مستطيل", 4, 6)];
shapes.forEach((shape) => {
  console.log(`مساحة ${shape.name}: ${shape.area().toFixed(2)}`);
});

شايف؟ نفس area()، نتايج مختلفة!


التجريد (Abstraction): ركز على المهم بس!

التجريد يخفي التعقيدات. في JS، استخدم interfaces افتراضية أو abstract classes (مش رسمي، بس نقدر نحاكيها).

مثال: وسيلة نقل – abstract class

class Vehicle {
  constructor(brand) {
    if (this.constructor === Vehicle) {
      throw new Error("مش تقدر تنشئ من abstract class!");
    }
    this.brand = brand;
  }

  move() {
    throw new Error("لازم تعيد تعريف move() في الكلاس الطفل!");
  }
}

class Bike extends Vehicle {
  move() {
    console.log(`${this.brand} بتتحرك بالدراجة!`);
  }
}

const myBike = new Bike("باجاج");
myBike.move(); // باجاج بتتحرك بالدراجة!

ده يمنع إنشاء كائنات غير مكتملة، مثال على التجريد في JavaScript.

نصايح عملية للمبتدئين في OOP JavaScript + مشاريع صغيرة

  • ابدأ صغير: جرب على To-Do List أو Calculator.
  • ممارسة يومية: استخدم CodePen، Replit، أو VS Code مع Node.js.
  • تجنب الأخطاء: متنساش new ، وخلي بالك من this في arrow functions (استخدم regular functions).

مشاريع مقترحة:

  • مكتبة كتب: كلاس Book يورث لـ EBook.
  • متجر إلكتروني: كلاس Product مع Cart.
  • لعبة Tic-Tac-Toe: كلاس Game مع Player.

اقرأ MDN عن Classes in JavaScript، أو كتاب "Eloquent JavaScript".


الخلاصة

البرمجة الكائنية في JavaScript للمبتدئين مش مجرد نظرية؛ هي أداة هتخلي مشاريعك أقوى وأسرع. مع الأمثلة دي، جربها دلوقتي وهتشوف السحر. عايز أمثلة أكتر أو توضيح حاجة؟ علق تحت، أو شارك تجربتك! لو عجبك، شاركه مع اللي زيك عشان يتعلموا. يلا، كود وخلاص، ونشوفك في المستوى اللي جاي! 🚀💻