البرمجة

النماذج الأولية والكائنات بلا __proto__ في جافاسكربت

توابع النماذج الأولية والكائنات بلا __proto__ في جافاسكربت

تعد جافاسكربت واحدة من اللغات البرمجية الديناميكية التي توفر مجموعة متنوعة من الأدوات والميزات للمطورين. من بين هذه الأدوات المهمة هي “النماذج الأولية” (prototypes) و”الكائنات بلا __proto__” (objects without __proto__). في هذا المقال، سوف نتناول هذين الموضوعين بشكل مفصل، بدءًا من مفهوم النماذج الأولية وكيفية استخدامها، وصولًا إلى مفهوم الكائنات بلا __proto__ وكيفية تأثير هذه الميزة على أداء جافاسكربت وتصميم التطبيقات.

النماذج الأولية (Prototypes) في جافاسكربت

النموذج الأولي هو مفهوم أساسي في جافاسكربت وهو يعد الآلية التي يتم من خلالها وراثة الخصائص والأساليب بين الكائنات. كل كائن في جافاسكربت لديه خاصية مخفية تُسمى __proto__ (والتي غالبًا ما تُسمى بالـ “prototype”)، وهي تشير إلى الكائن الذي يتم وراثته منه. هذه الآلية تُسهل الوصول إلى الوظائف المتوارثة من الكائنات الأخرى. وعادةً ما يُستخدم النموذج الأولي لإضافة خصائص ودوال مشتركة بين الكائنات في جافاسكربت.

عند إنشاء كائن جديد في جافاسكربت، مثلًا باستخدام الكلمة المفتاحية new، يتم ربط هذا الكائن بنموذج أولي. بمعنى آخر، يتم ربطه بكائن يسمى “النموذج الأولي” والذي يحتوي على خصائص ودوال يمكن استخدامها أو تعديلها من قبل الكائن الذي تم إنشاؤه.

على سبيل المثال، عندما يتم إنشاء كائن باستخدام “الدالة الإنشائية” (constructor function) في جافاسكربت:

javascript
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.sayHello = function() { console.log("Hello, my name is " + this.name); }; let person1 = new Person("Ahmed", 25); person1.sayHello(); // "Hello, my name is Ahmed"

في هذا المثال، يتم إنشاء كائن جديد باستخدام دالة الإنشاء Person. الخصائص name و age تم إضافتها مباشرة إلى الكائن، بينما الدالة sayHello تم إضافتها عبر النموذج الأولي Person.prototype.

كيفية عمل النماذج الأولية

كل كائن في جافاسكربت يحتوي على خاصية __proto__ التي تشير إلى نموذج أولي. عندما يتم الوصول إلى خاصية أو دالة غير موجودة في الكائن نفسه، جافاسكربت تبحث عنها في سلسلة النماذج الأولية لهذا الكائن. هذه السلسلة تُسمى بـ “سلسلة النموذج الأولي” (Prototype Chain). يتم البحث عن الخاصية في الكائن الحالي، وإذا لم يتم العثور عليها، يتم الانتقال إلى النموذج الأولي المرتبط بالكائن، وهكذا حتى الوصول إلى النهاية.

على سبيل المثال:

javascript
let obj = { name: "John" }; let person = Object.create(obj); person.age = 30; console.log(person.name); // "John" console.log(person.age); // 30

في هذا المثال، الكائن person لا يحتوي على الخاصية name، لذلك يتم الرجوع إلى النموذج الأولي (الكائن obj) للبحث عنها.

الكائنات بلا __proto__

منذ جافاسكربت 6 (ECMAScript 2015)، تم تقديم ميزة Object.create(null)، التي تتيح للمطورين إنشاء كائنات لا تحتوي على خاصية __proto__. هذه الكائنات تُسمى بـ “الكائنات بدون __proto__“. في هذه الحالة، لا يوجد للكائن سلسلة من النماذج الأولية وبالتالي لا يمكن أن يرث الكائن من أي نموذج أولي، وهذا يعني أن الكائن لا يحتوي على أي خصائص مثل toString أو hasOwnProperty التي توجد في الكائنات العادية.

إنشاء كائن بدون __proto__ قد يكون مفيدًا في بعض الحالات مثل عندما ترغب في تخزين بيانات في كائن دون أن تكون هناك حاجة للإرث أو إذا كنت ترغب في تحسين الأداء في بعض التطبيقات التي تتطلب إنشاء كائنات “نظيفة” بعيدًا عن الإرث غير الضروري.

على سبيل المثال:

javascript
let obj = Object.create(null); obj.name = "Ali"; obj.age = 35; console.log(obj.name); // "Ali" console.log(obj.age); // 35

في هذا المثال، الكائن obj تم إنشاؤه باستخدام Object.create(null). هذا الكائن لا يحتوي على خاصية __proto__ وبالتالي لا يوجد أي إرث من الكائنات الأساسية في جافاسكربت.

فائدة الكائنات بلا __proto__

السبب الرئيسي لاستخدام كائنات بلا __proto__ هو تجنب بعض السلوكيات غير المرغوب فيها التي قد تظهر عند استخدام الكائنات العادية. على سبيل المثال، عندما يتم إضافة خصائص أو دوال إلى كائن، قد توجد خصائص مثل toString أو hasOwnProperty التي تكون موجودة في النماذج الأولية. في بعض الأحيان، قد يؤدي هذا إلى حدوث تصادمات أو نتائج غير متوقعة، خصوصًا إذا كنت تستخدم الكائنات كمجموعات لتخزين البيانات.

الكائنات بدون __proto__ توفر بنية بيانات “نظيفة”، خالية من الإرث الذي قد يسبب تعقيدًا غير ضروري. هذا يساعد في تجنب التصادمات مع الخصائص والطرق التي يتم توفيرها من قبل الكائنات الأصلية في جافاسكربت.

المزايا والتحديات

المزايا
  1. الأداء المحسن: في بعض الحالات، يمكن أن يؤدي استخدام الكائنات بدون __proto__ إلى تحسين الأداء، خاصة في التطبيقات التي تتطلب تخزين كميات كبيرة من البيانات.

  2. الحماية ضد التصادمات: الكائنات بدون __proto__ تقلل من احتمال حدوث تصادمات بين البيانات والطرق الموروثة من النماذج الأولية.

  3. المرونة: يوفر لك Object.create(null) طريقة لإنشاء كائنات يتمتع كل منها بنموذج أولي مخصص، ما يجعلها مفيدة في بعض التطبيقات المتقدمة.

التحديات
  1. فقدان وظائف مدمجة: الكائنات التي يتم إنشاؤها بهذه الطريقة لا تحتوي على وظائف مدمجة مثل hasOwnProperty أو toString. وبالتالي، إذا كنت بحاجة إلى هذه الوظائف، عليك إعادة تعريفها يدويًا.

  2. التعقيد الإضافي: في بعض الأحيان، يمكن أن يؤدي تجنب النماذج الأولية إلى زيادة تعقيد الكود بسبب الحاجة إلى التعامل مع وظائف إضافية بشكل منفصل.

حالات الاستخدام

يمكن أن تكون الكائنات بلا __proto__ مفيدة في مجموعة متنوعة من التطبيقات. على سبيل المثال:

  1. إنشاء قواميس (Dictionaries): في حالة رغبتك في تخزين بيانات حيث يكون الكائن يحتوي فقط على أزواج من المفاتيح والقيم، يمكن أن تكون الكائنات بلا __proto__ مثالية لتجنب أي مشاكل متعلقة بالإرث.

  2. تحسين الأداء في أنظمة المعالجة المكثفة: في التطبيقات التي تتطلب معالجة بيانات كبيرة مثل نظم قواعد البيانات أو معالجة النصوص، يمكن أن يؤدي استخدام هذه الكائنات إلى تسريع الأداء بشكل ملحوظ.

الاستنتاج

تعتبر النماذج الأولية آلية أساسية لفهم كيفية عمل الوراثة في جافاسكربت. بفضل النماذج الأولية، يتمكن المطورون من إنشاء كائنات مرنة وقوية تشارك الخصائص والوظائف بسهولة. ومع ذلك، فإن الكائنات بلا __proto__ توفر بديلاً مفيدًا عندما تحتاج إلى كائنات بسيطة خالية من الخصائص الموروثة، وهو ما يمكن أن يكون مفيدًا لتحسين الأداء وتجنب التصادمات غير المرغوب فيها.