Prototype

في JavaScript، مفهوم Prototype (النموذج الأولي) هو أحد أهم المفاهيم في البرمجة الكائنية التوجه (OOP) في هذه اللغة، ويُعد حجر الأساس لنظام الوراثة فيها.

🧠 ما هو Prototype في JavaScript؟

في JavaScript، كل كائن (object) له خاصية داخلية تُسمى [[Prototype]]. يمكنك الوصول إليها (بطريقة غير رسمية) باستخدام خاصية __proto__، أو (بطريقة رسمية) باستخدام Object.getPrototypeOf(obj).

الـ prototype هو كائن يُستخدم كقالب (template) للكائنات الأخرى لوراثة خصائصه ودواله.

🏗️ الوراثة باستخدام Prototype

عندما تبحث عن خاصية في كائن ولم تجدها، يبحث JavaScript تلقائيًا في كائن الـ prototype المرتبط به، وهكذا حتى يصل إلى نهاية السلسلة (null).

let person = {
  greet() {
    console.log("Hello!");
  }
};

let student = {
  study() {
    console.log("Studying...");
  }
};

// ربط student بـ person
student.__proto__ = person;

student.study(); // Studying...
student.greet(); // Hello! ← ورثها من person
JavaScript

⚠️ تنبيه: استخدام __proto__ غير مستحسن في المشاريع الحقيقية. يُفضل استخدام Object.create() أو Object.setPrototypeOf().

🔄 إنشاء الوراثة باستخدام الدوال البنائية (Constructor Functions)

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}`);
};

let p = new Person("Ali");
p.sayHello(); // Hello, my name is Ali
JavaScript

p يرث من Person.prototype

📦 فوائد واستخدامات prototype

توفير الذاكرة

بدلاً من إنشاء نسخة من نفس الدالة لكل كائن، يمكن وضع الدالة في prototype ليتم مشاركتها بين كل النسخ.

function Car(model) {
  this.model = model;
}

Car.prototype.drive = function() {
  console.log(`${this.model} is driving`);
};

let c1 = new Car("Toyota");
let c2 = new Car("Honda");

console.log(c1.drive === c2.drive); // true ✅
JavaScript
✅ إنشاء سلاسل وراثة

يمكنك بناء سلسلة وراثة معقدة:

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(`${this.name} makes a noise`);
};

function Dog(name) {
  Animal.call(this, name);
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log(`${this.name} barks`);
};

let d = new Dog("Rex");
d.speak(); // Rex makes a noise
d.bark();  // Rex barks
JavaScript
🧪 حالات مهمة ومفاهيم مرتبطة
🔍 ما الفرق بين __proto__ و prototype؟
العنصرالمعنى
obj.__proto__يشير إلى prototype الذي يرث منه الكائن
Func.prototypeالكائن الذي سيتم استخدامه كـ prototype لأي كائن يتم إنشاؤه بهذه الدالة
❓ ما هو Object.create()؟

ينشئ كائن جديد ويربطه بكائن موجود كـ prototype.

let animal = {
  makeSound() {
    console.log("Generic sound");
  }
};

let dog = Object.create(animal);
dog.makeSound(); // Generic sound
JavaScript

🔄 تغيير الـ Prototype بعد الإنشاء

let cat = {};
Object.setPrototypeOf(cat, animal);

cat.makeSound(); // Generic sound
JavaScript
📉 مخاطر التلاعب بـ prototype
  • يمكن أن يؤدي إلى تعقيد في تتبع الأخطاء.
  • يجعل الكود أقل وضوحًا.
  • التلاعب بـ Object.prototype يؤثر على كل الكائنات، وقد يسبب مشاكل:
Object.prototype.sayHi = function() {
  console.log("Hi from Object");
};

let x = {};
x.sayHi(); // Hi from Object ← خطير!
JavaScript
📚 ملخص الفوائد
الفائدةالتوضيح
تقليل استهلاك الذاكرةتشارك الدوال عبر جميع النسخ
دعم الوراثةبدون الحاجة للفئات
التحكم الكامل في السلسلةيمكن ربط prototype يدوياً أو باستخدام دوال
🎯 استخدامات شائعة
  • بناء نماذج كائنية قبل ظهور class.
  • إضافة دوال إلى كائنات أنشأتها دوال بنائية.
  • إنشاء مكتبات خفيفة دون class.
  • تعزيز الكائنات بميزات إضافية دون تعديلها مباشرة.

🆕 استخدام class (واجهة أحدث للـ prototype)

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

  greet() {
    console.log(`Hi, I'm ${this.name}`);
  }
}

let p = new Person("Sara");
p.greet(); // Hi, I'm Sara
JavaScript

خلف الكواليس، class هو مجرد غلاف أنيق للـ prototype.

🧩 حالات تحتاج فهم عميق للـ prototype
  1. التحقق من الوراثة:
console.log(d instanceof Dog);     // true
console.log(d instanceof Animal);  // true
JavaScript

التحقق من سلسلة prototype:

console.log(Object.getPrototypeOf(d) === Dog.prototype);     // true
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
JavaScript

فهم constructor:

console.log(d.constructor === Dog); // true
JavaScript
✅ خلاصة:
  • Prototype هو أساس الوراثة في JavaScript.
  • يمكنك استخدامه لتوفير الذاكرة وإنشاء هيكل وراثي.
  • بالرغم من وجود class، يظل فهم prototype ضروريًا لفهم كيف تعمل JavaScript فعليًا.
  • استخدامه بطريقة صحيحة يساعد على كتابة كود نظيف وفعال.