يرجى نسيان كل المعرفة الموجهة نحو الكائن الذي تعلمته من قبل. فقط فكر في وضع السباق هنا. نعم ، إنه سباق.
في الآونة الأخيرة ، أشاهد 24 ساعة من Le Mans ، وهو حدث شهير في فرنسا. أسرع سيارة تسمى النموذج الأولي. على الرغم من أن هذه السيارات تصنعها الشركات المصنعة مثل "Audi" أو "Peugeot" ، إلا أنها ليست من نوع السيارات التي تراها في الشارع أو على الطريق السريع. وهي مصنوعة خصيصًا لأحداث التحمل عالية السرعة.
تستثمر الشركة المصنعة مبالغ ضخمة من المال لتطوير وتصميم وتصنيع هذه السيارات النموذجية ، ويحاول المهندسون دائمًا جعل هذا المشروع إلى أقصى الحدود. أجروا تجارب مختلفة على السبائك والوقود الحيوي وتكنولوجيا الكبح وتكوين المركب وخصائص السلامة للإطارات. بمرور الوقت ، تم تحسين بعض التقنيات في هذه التجارب مرارًا وتكرارًا ودخل خط الإنتاج الرئيسي للمركبات. قد تكون بعض التكنولوجيا في السيارة التي تقودها قد تم عرضها لأول مرة على النموذج الأولي للسباق.
يمكنك أيضًا القول إن هذه المركبات السائدة ترث النماذج التقنية من سيارات السباق.
حتى الآن ، لدينا أساس لمناقشة النموذج الأولي والميراث في JavaScript. على الرغم من أنه ليس جيدًا مثل نمط الميراث الكلاسيكي الذي تعرفه في C ++ أو Java أو C#، إلا أنه قوي وربما أكثر مرونة.
JavaScript مليئة بالأشياء ، التي تشير إلى الأشياء بالمعنى التقليدي ، أي "كيان واحد يحتوي على الحالة والسلوك". على سبيل المثال ، صفيف في JavaScript هو كائن يحتوي على العديد من القيم ويحتوي على طرق الدفع والعكس والبوب.
var myarray = [1 ، 2] ؛ myarray.push (3) ؛ myarray.reverse () ؛ myarray.pop () ؛ var length = myarray.length ؛
الآن السؤال هو ، من أين يأتي الدفع؟ اللغات الثابتة التي ذكرناها في وقت سابق تستخدم "بناء جملة الفئة" لتحديد بنية الكائنات ، ولكن JavaScript هي لغة بدون "بناء جملة الفئة" ولا يمكنها تحديد كل كائن صفيف باستخدام بناء جملة الصفيف ". ولأن JavaScript هي لغة ديناميكية ، يمكننا وضع أساليب على الكائنات كما نحتاجها بالفعل. على سبيل المثال ، يحدد الكود التالي كائن نقطة يستخدم لتمثيل نقطة في الفضاء ثنائي الأبعاد ، ويحدد أيضًا طريقة إضافة.
var point = {x: 10 ، y: 5 ، add: function (pointpoint) {this.x += orlypoint.x ؛ this.y += OlderPoint.y }} ؛ومع ذلك ، فإن الممارسات أعلاه ليست قابلة للتطوير للغاية. نحتاج إلى التأكد من أن كل كائن نقطة يحتوي على طريقة إضافة ، ونريد أيضًا أن تشارك جميع كائنات النقاط تنفيذ نفس طريقة إضافة ، بدلاً من إضافة هذه الطريقة يدويًا إلى كل كائن نقطة. هذا هو المكان الذي يأتي فيه النموذج الأولي.
في JavaScript ، يظل كل كائن مخفيًا - إشارة إلى كائن آخر ، يُعرف أيضًا باسم النموذج الأولي. الصفيف الذي أنشأناه قبل المراجع كائن النموذج الأولي ، وكذلك كائنات النقطة التي أنشأناها بأنفسنا. كما ذكر أعلاه ، يتم إخفاء مراجع النموذج الأولي ، ولكن هناك أيضًا تطبيقات لـ ECMASCRIPT (الاسم الرسمي لـ JavaScript) التي يمكنها الوصول إلى مرجع النموذج الأولي هذا من خلال سمة __proto__ لكائن (مثل Google Chrome). من الناحية المفاهيمية ، يمكننا معالجة الأشياء كعلاقات مشابهة لتلك الممثلة في النموذج 1-prototype.
الشكل 1
إذا نظرنا إلى المستقبل ، سيتمكن المطورون من استخدام وظيفة getProtoTypeOF بدلاً من سمة __proto__ للحصول على إشارات إلى النموذج الأولي للكائن. في وقت كتابة هذا المقال ، يمكن بالفعل استخدام وظيفة combor.getProtypeOF في متصفحات Google Chrome و Firefox و IE9. ستنفذ المزيد من المتصفحات هذه الميزة في المستقبل لأنها بالفعل جزء من معيار ECMASCRIPT. يمكننا استخدام الكود التالي لإثبات أن كائنات MyArray و DOT التي أنشأناها تشير إلى كائنين مختلفين للنموذج.
بالنسبة لبقية هذه المقالة ، سأقوم باستخدام وظائف __proto__ و Object.getProtypeOF ، وذلك أساسًا لأن __proto__ أسهل في التعرف على الرسوم البيانية والجمل. يجب أن نتذكر أنه (__proto__) ليس هو المعيار ، ودالة الكائن .
ما الذي يجعل النموذج الأولي مميزًا جدًا؟
لم نرد على هذا السؤال: من أين يأتي الضغط في صفيف؟ الجواب هو: إنه يأتي من كائن النموذج الأولي myarray. الشكل 2 هو لقطة شاشة لتصحيح النصوص في الكروم. لقد أطلقنا على Object.getPrototypeof طريقة لعرض كائن النموذج الأولي لـ MyArray.
الشكل 2
لاحظ أن هناك العديد من الطرق في كائن النموذج الأولي الخاص بـ MyArray ، بما في ذلك تلك التي تسمى الأساليب Push و POP و OPERN في أمثلة التعليمات البرمجية. لذلك ، تتضمن طريقة الدفع كائن النموذج الأولي ، ولكن كيف تشير طريقة myarray إلى ذلك؟
myarray.push (3) ؛
الخطوة الأولى لفهم كيفية عملها هي إدراك أن النموذج الأولي ليس مميزًا. النموذج الأولي هو مجرد كائن عادي. يمكنك إضافة طرق وخصائص إلى النموذج الأولي ومعاملتها ككائنات JavaScript الأخرى. ومع ذلك ، لتطبيق بيان "الخنزير" في رواية جورج أورويل "مزرعة الحيوانات" - يجب أن تكون جميع الأشياء متساوية ، لكن بعض الأشياء (أولئك الذين يتبعون القواعد) أكثر مساواة من غيرها.
الكائنات النموذجية في JavaScript خاصة بالفعل لأنها تتبع القواعد التالية. عندما نخبر JavaScript أننا نريد أن نسمي طريقة دفع الكائن ، أو قراءة خاصية X للكائن ، فإن وقت التشغيل سيبحث أولاً عن الكائن نفسه. إذا لم يتمكن وقت التشغيل من العثور على ما يريد ، فإنه يتبع مرجع __proto__ والنموذج الأولي للكائن للبحث عن العضو. عندما نسمي طريقة دفع MyArarray ، لا تجد JavaScript طريقة الدفع على كائن MyArray ، ولكن على كائن النموذج الأولي لـ MyArray ، لذلك يطلق JavaScript هذه الطريقة (انظر الشكل 3).
الشكل 3
يشير السلوك الموضح أعلاه إلى كائن نفسه يرث أي طريقة أو خاصية على النموذج الأولي. في JavaScript ، يتم تحقيق الميراث فعليًا دون استخدام بناء جملة الفصل. تمامًا مثل السيارة التي ترث التكنولوجيا المقابلة من النموذج الأولي للسباق ، يمكن لكائن JavaScript أيضًا أن يرث ميزات وظيفية من كائن النموذج الأولي.
يوضح الشكل 3 أيضًا أن كل كائن صفيف يمكنه أيضًا الحفاظ على حالته وأعضائه. عند طلب سمة طول MyArray ، ستحصل JavaScript على قيمة سمة الطول في MyArray دون قراءة القيمة المقابلة في النموذج الأولي. يمكننا "الكتابة فوق" طريقة الدفع عن طريق إضافة طريقة مثل الدفع إلى الكائن. سيؤدي ذلك إلى إخفاء تطبيق طريقة الدفع بشكل فعال في النموذج الأولي.
السحر الحقيقي للنماذج الأولية في JavaScript هو كيف تحافظ كائنات متعددة على الإشارات إلى نفس كائن النموذج الأولي. على سبيل المثال ، إذا أنشأنا صفيفتين مثل هذا:
var myarray = [1 ، 2] ؛ var yourarray = [4 ، 5 ، 6] ؛
ثم ستشارك هاتان المصفوفتان نفس كائن النموذج الأولي ، ويتم تقييم الكود التالي إلى صواب:
Object.getPrototypeof (myarray) === Object.getPrototypeof (yourarray) ؛
إذا أشارنا إلى طريقة الدفع على كائنين صفيف ، فسيبحث JavaScript عن طريقة الدفع المشتركة على النموذج الأولي.
الشكل 4
توفر الكائنات النموذجية في JavaScript وظائف الميراث ، وفي الوقت نفسه ، يتم تنفيذ مشاركة هذه الطريقة. النموذج الأولي أيضا بالسلاسل. بمعنى آخر ، نظرًا لأن كائن النموذج الأولي هو مجرد كائن ، يمكن الحفاظ على كائن واحد أولي إلى مرجع إلى كائن نموذج أولي آخر. إذا قمت بإعادة النظر في الشكل 2 ، يمكنك أن ترى أن خاصية __proto__ للنموذج الأولي هي قيمة غير فنية تشير إلى نموذج أولي آخر. عندما يبحث JavaScript عن أعضاء مثل طريقة الدفع ، فإنه يتحقق من كل كائن على طول السلسلة المرجعية النموذجية حتى يتم العثور عليه ، أو يصل إلى نهاية سلسلة النموذج الأولي. سلاسل النموذج الأولي تفتح مسارًا مرنًا للميراث والمشاركة.
السؤال التالي الذي قد تطرحه هو: كيف يمكنني إعداد مراجع النموذج الأولي لتلك الكائنات المخصصة؟ على سبيل المثال ، كائن النقطة المستخدمة سابقًا ، كيف يمكنني إضافة طريقة إضافة إلى كائن النموذج الأولي وروث الطريقة من كائنات نقاط متعددة؟ قبل الإجابة على هذا السؤال ، نحتاج إلى إلقاء نظرة على الوظائف.
الوظائف في JavaScript هي أيضا كائنات. مثل هذا البيان يجلب العديد من النتائج المهمة ، ولن نغطي جميع الأمور في هذه المقالة. من بينها ، فإن القدرة على تعيين وظيفة لمتغير وتمرير وظيفة كمعلمة إلى دالة أخرى تشكل النموذج الأساسي للتعبير عن برمجة JavaScript الحديثة.
ما نحتاج إلى الانتباه إليه هو أن الوظيفة نفسها هي كائن ، لذلك يمكن أن يكون للوظيفة أساليبها وخصائصها الخاصة والرجوع إلى كائن النموذج الأولي. دعنا نناقش معنى الكود التالي.
// هذا سيعود صحيحًا: typeof (Array) === "وظيفة" // مثل هذا التعبير هو أيضًا: object.getProtypeOf (Array) === object.getProtypeOf (function () {}) // هذا التعبير هو نفسه: Array.Prototype! = null!يثبت السطر الأول في الكود أن الصفيف في JavaScript هو وظيفة. سنرى كيفية استدعاء وظيفة الصفيف لإنشاء كائن صفيف جديد. يثبت السطر التالي من التعليمات البرمجية أن كائن المصفوفة يستخدم نفس النموذج الأولي مثل أي كائن وظيفة آخر ، تمامًا كما نرى أن النموذج الأولي نفسه مشاركة بين كائنات الصفيف. يثبت السطر الأخير من التعليمات البرمجية أن وظيفة الصفيف لها خاصية نموذجية ، وتشير خاصية النموذج الأولي هذه إلى كائن صالح. خاصية النموذج الأولي مهم للغاية.
كل كائن دالة في JavaScript لديه خاصية النموذج الأولي. لا تخلط أبداً سمة __proto__ لهذه الخاصية النموذجية. إنها غرض مختلف ، ولا يشيرون إلى نفس الكائن.
// return TrueObject.getPrototypeof (Array)! = Array.Protypee
Array .__ Proto__ يوفر نموذجًا أوليًا. يرجى التعامل معها ككائن ورثته وظيفة الصفيف.
Array.Protoype يوفر كائنات النموذج الأولي لجميع المصفوفات. بمعنى أنه يوفر كائنات نموذجية لكائنات الصفيف مثل myarray ، ويحتوي أيضًا على طرق ترثها جميع المصفوفات. يمكننا كتابة بعض التعليمات البرمجية لإثبات هذه الحقيقة.
// truearray.prototype == object.getPrototypeof (myarray) // إنه أيضًا truearray.prototype == object.getPrototypeof (yourarray) ؛
يمكننا أيضًا استخدام هذه المعرفة الجديدة لإعادة رسم الرسم البياني السابق.
الشكل 5
بناءً على ما تعرفه ، تخيل عملية إنشاء كائن جديد وجعل الكائن الجديد يتصرف مثل صفيف. طريقة واحدة هي استخدام الكود التالي.
// قم بإنشاء كائن فارغ جديد var o = {} ؛ // الموروث من نفس النموذج الأولي ، كائن صفيف o .__ proto__ = array.prototype ؛ // الآن يمكننا استدعاء أي طريقة للمصفوفة ... o.push (3) ؛على الرغم من أن هذا الرمز مثير للاهتمام ويعمل ، إلا أن المشكلة هي أنه لا تدعم كل بيئة JavaScript خصائص كائن قابلة للكتابة. لحسن الحظ ، لدى JavaScript آلية قياسية لإنشاء كائنات. لا يتطلب الأمر سوى مشغل واحد لإنشاء كائنات جديدة ، وتعيين مرجع __proto__ للكائن الجديد ، وهو المشغل "الجديد".
var o = new array () ؛ o.push (3) ؛
المشغل الجديد في JavaScript لديه ثلاث مهام أساسية. أولاً ، يخلق كائنًا فارغًا جديدًا. بعد ذلك ، سيتم تعيين خاصية __proto__ للكائن الجديد لمطابقة خصائص النموذج الأولي للوظيفة المستدعية. أخيرًا ، يقوم المشغل باستدعاء الوظيفة ، وتمرير الكائن الجديد كمرجع "هذا". إذا كنت ترغب في تمديد الخطين الأخيرين من التعليمات البرمجية ، فسيصبح هذا هو الموقف التالي:
var o = {} ؛ o .__ proto__ = array.prototype ؛ array.call (o) ؛ o.push (3) ؛تتيح لك طريقة استدعاء الوظيفة تحديد الكائن المشار إليه بواسطة "هذا" داخل الوظيفة عند استدعاء الوظيفة. بالطبع ، يحتاج مؤلف الوظيفة إلى تنفيذ مثل هذه الوظيفة في هذه الحالة. بمجرد أن ينشئ المؤلف هذه الوظيفة ، يمكن تسميتها بأنها مُنشئ.
مُنشئ
المُنشئون هم نفس الوظائف العادية ، ولكن لديهم خصائصان خاصتين التاليتين.
الصفيف هو مثال على مُنشئ. يجب استخدام وظيفة الصفيف مع المشغل الجديد ، ويتم رسملة خطاب الصفيف الأولي. يتضمن JavaScript Array كدالة مدمجة ، ويمكن لأي شخص كتابة مُنشئه. في الواقع ، يمكننا أخيرًا كتابة مُنشئ لكائنات النقطة التي تم إنشاؤها مسبقًا.
var point = function (x ، y) {this.x = x ؛ this.y = y ؛ this.add = function (pointpoint) {this.x += OlderPoint.x ؛ this.y += OlderPoint.y }} var p1 = نقطة جديدة (3 ، 4) ؛ var p2 = نقطة جديدة (8 ، 6) ؛ p1.add (p2) ؛في الكود أعلاه ، نستخدم المشغل الجديد ووظيفة النقطة لبناء كائن نقطة ، والذي يحتوي على سمات X و Y وطريقة إضافة. يمكنك أن تتخيل النتيجة النهائية كما هو موضح في الشكل 6.
الشكل 6
المشكلة الآن هي أنه لا تزال هناك طريقة إضافة منفصلة في كل من كائنات نقاطنا. باستخدام النموذج الأولي والميراث الذي تعلمناه ، نفضل نقل طريقة إضافة كائن النقطة من كل مثيل نقطة إلى نقطة. النموذج. لتحقيق تأثير وراثة طريقة إضافة ، كل ما نحتاج إلى فعله هو تعديل كائن النموذج.
var point = function (x ، y) {this.x = x ؛ this.y = y ؛} point.prototype.add = function (pointpoint) {this.x += otherpoint.x ؛ this.y += ortherpoint.y ؛} var p1 = نقطة جديدة (3 ، 4) ؛ var p2 = نقطة جديدة (8 ، 6) ؛ p1.add (p2) ؛تم الانتهاء من المهمة! لقد أكملنا للتو وضع الميراث للنموذج الأولي في JavaScript!
الشكل 7
لخص
آمل أن تساعدك هذا المقال في الكشف عن لغز مفاهيم النموذج الأولي JavaScript. ما رأيته في البداية هو كيف سمح النموذج الأولي لتكوين وظائف من كائنات أخرى ، ثم رأيت كيفية الجمع بين المشغل والمشغل الجديد لبناء الكائن. ما هو مذكور هنا هو مجرد الخطوة الأولى لإلغاء تأمين قوة ومرونة النموذج الأولي للكائن. تشجعك هذه المقالة على اكتشاف وتعلم معلومات جديدة حول النماذج الأولية ولغات JavaScript لنفسك.
أيضا ، يرجى القيادة بعناية. لن تعرف أبدًا التكنولوجيا (المعيبة) التي سترثها هذه المركبات التي تسافر على الطريق من نماذجها الأولية.
الرابط الأصلي: Script Junkie Translation: Bole Online - Emje