الكلاس في لغة JavaScript


الكلاس في لغة JavaScript

يا هلا! اليوم بنتكلم عن الكلاسات في جافاسكريبت. تدري، الكلاسات هي طريقة حلوة ومرتبة عشان تسوي كائنات (objects) وتورث منها. هي بالأساس "سكر نحوي" (syntactic sugar) فوق نظام الـ prototypes اللي جافاسكريبت مبنية عليه، يعني ما غيرت طريقة عمل جافاسكريبت الأساسية، بس خلت الكود شكله أنظف وأسهل للقراءة، خصوصاً لو جاي من لغات زي جافا أو C#.

كيف تسوي كلاس؟

مرة سهل! تستخدم الكلمة المفتاحية class وبعدها اسم الكلاس. دايمًا خلي أول حرف من اسم الكلاس كابيتال (PascalCase) عشان يكون الكود أنظف.

class Person {
  // هنا بنحط الخصائص والدوال
}

الـ Constructor (الباني)

هذي دالة خاصة تتنفذ أول ما تسوي كائن جديد من الكلاس. تستخدمها عشان تهيئ الخصائص الأولية للكائن.

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

ملاحظة سريعة: الكلمة this هنا تشير للكائن اللي قاعدين ننشئه حاليًا.

إضافة دوال (Methods) للكلاس

تقدر تضيف أي دالة تحتاجها داخل الكلاس، وهذي الدوال بتكون متاحة لكل الكائنات اللي تسويها من الكلاس.

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

  sayHello() {
    console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">مرحباً، اسمي ${this.name} وعمري ${this.age} سنة.</code>);
  }

  celebrateBirthday() {
    this.age++;
    console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">عيد ميلاد سعيد! عمري الآن ${this.age} سنة.</code>);
  }
}

كيف تسوي كائن (Object) من الكلاس؟

بعد ما سويت الكلاس، عشان تستخدمه، لازم تسوي منه "نسخة" أو "كائن". تستخدم الكلمة المفتاحية new.

const person1 = new Person('أحمد', 30);
person1.sayHello(); // مرحباً، اسمي أحمد وعمري 30 سنة.
person1.celebrateBirthday(); // عيد ميلاد سعيد! عمري الآن 31 سنة.

const person2 = new Person('سارة', 25);
person2.sayHello(); // مرحباً، اسمي سارة وعمري 25 سنة.

الوراثة (Inheritance)

هنا يبدأ الشغل الصح! تقدر تخلي كلاس يورث من كلاس ثاني. يعني الكلاس الابن ياخذ كل الخصائص والدوال من الكلاس الأب، ويقدر يضيف عليها أو يعدل فيها. نستخدم الكلمة extends.

class Student extends Person {
  constructor(name, age, studentId) {
    super(name, age); // ننادي على constructor الأب
    this.studentId = studentId;
  }

  study() {
    console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">${this.name} يدرس الآن برقم جامعي ${this.studentId}.</code>);
  }

  // نقدر نعدل على دالة من الأب (Method Overriding)
  sayHello() {
    console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">أنا طالب، اسمي ${this.name} وعمري ${this.age} سنة ورقمي الجامعي هو ${this.studentId}.</code>);
  }
}

const student1 = new Student('فاطمة', 20, 'S12345');
student1.sayHello(); // أنا طالب، اسمي فاطمة وعمري 20 سنة ورقمي الجامعي هو S12345.
student1.study(); // فاطمة يدرس الآن برقم جامعي S12345.
student1.celebrateBirthday(); // عيد ميلاد سعيد! عمري الآن 21 سنة.

تذكر: دائمًا لازم تنادي على super() في constructor الكلاس الابن قبل ما تستخدم this، إذا كان الكلاس الأب عنده constructor.

الدوال الثابتة (Static Methods)

أحياناً تحتاج دالة تكون مرتبطة بالكلاس نفسه مو بالكائنات اللي تنشئها منه. هنا يجي دور static. هذي الدوال تقدر تناديها مباشرة على الكلاس بدون ما تسوي new منه.

class Calculator {
  static add(a, b) {
    return a + b;
  }

  static subtract(a, b) {
    return a - b;
  }
}

console.log(Calculator.add(5, 3)); // 8
console.log(Calculator.subtract(10, 4)); // 6
// هذا خطأ: const calc = new Calculator(); calc.add(1,2);

الـ Getters والـ Setters

هذي دوال خاصة تستخدمها للتحكم بكيفية الوصول للخصائص وتعديلها. تخلي الكود أكثر أمانًا ومرونة.

class Product {
  constructor(name, price) {
    this._name = name; // نستخدم _ كإشارة أن هذا المتغير خاص (convention)
    this._price = price;
  }

  get name() {
    return this._name.toUpperCase();
  }

  set price(newPrice) {
    if (newPrice < 0) {
      console.error("السعر لا يمكن أن يكون سالبًا!");
      return;
    }
    this._price = newPrice;
  }

  get price() {
    return this._price;
  }
}

const item = new Product('لابتوب', 1200);
console.log(item.name); // لابتوب (LAPTOM) - هنا ينادي على الـ getter
item.price = 1300; // هنا ينادي على الـ setter
console.log(item.price); // 1300
item.price = -50; // السعر لا يمكن أن يكون سالبًا!

ملاحظة: في المثال فوق، _name هو مجرد اصطلاح (convention) للإشارة إلى أن الخاصية "شبه خاصة". في الواقع، لا يزال بإمكانك الوصول إليها مباشرة item._name.

الخصائص الخاصة (Private Fields) - ميزة جديدة

مع التحديثات الجديدة في جافاسكريبت، صار فيه طريقة فعلية لتعريف خصائص خاصة باستخدام علامة #. هذي الخصائص ما تقدر توصلها من خارج الكلاس.

class Account {
  #balance; // خاصية خاصة

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

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
      console.log(<code dir="ltr" style="background:#f3f4f6; color:#0056b3; padding:2px 6px; border-radius:4px; font-family:monospace; direction:ltr !important; display:inline-block;">تم إيداع ${amount}. الرصيد الحالي: ${this.#balance}</code>);
    }
  }

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

const myAccount = new Account(1000);
myAccount.deposit(500); // تم إيداع 500. الرصيد الحالي: 1500
// console.log(myAccount.#balance); // خطأ! لا يمكن الوصول للخاصية الخاصة من الخارج
console.log(myAccount.getBalance()); // 1500

خلاصة الكلام

الكلاسات في جافاسكريبت أداة قوية ومرنة جدًا لتنظيم الكود وبناء تطبيقات معقدة بشكل أسهل وأوضح. استخدمها صح وبشوف كيف الكود حقك بيصير أنظف وأسهل للصيانة. بالتوفيق!