لفهم النموذج الأولي في JS ، يجب أولاً فهم المفاهيم التالية
1. كل شيء في JS هو كائن
2. كل شيء في JS مشتق من كائن ، أي نقطة نهاية سلسلة النموذج الأولي لجميع الأشياء تشير إلى Object.protypee
// ["Constructor" ، "ToString" ، "tolocalestring" ، "valueof" ، "hasownproperty" ، "isprototypeof" ، // "propertyisenumerable" ، "__definegetter__" ، "__ lookupgetter__" ، "__definesetter__" ، // " console.log (object.getOntOnpropertyNames (Object.prototype)) ؛
3. العلاقة الدقيقة بين البنائين والحالات (الكائنات) في JS
يحدد المنشئون النماذج الأولية للاتفاق على مواصفات مثيلاتهم ، ثم بناء مثيلات من خلال جديدة. وظيفتها هي إنتاج كائنات.
المُنشئ (الطريقة) نفسه هو مثيل للطريقة (الوظيفة) ، لذلك يمكن العثور عليه أيضًا لـ __proto __ (protochain)
الكائن / الدالة f () {} هذا هو المُنشئ ، ويتم توفير أحدهم بواسطة API الأصلي JS ، والآخر مخصص
كائن جديد () / جديد f () هو مثيل
لا يمكن عرض الأمثلة إلا على "فقط" لمعرفة النموذج الأولي الذي تم صنعه بناءً على.
النموذج الأولي الذي "لا يمكن" إعادة تعريف المثيل ثم يخدع نفسه لإنشاء مثيل للمثال.
تدرب على إنتاج المعرفة الحقيقية ، وفقط من خلال مراقبة/التفكير في نفسك ، يمكنك أن تفهم حقًا:
// دعونا أولاً نلقي نظرة على ما هو مُنشئ // وظيفة فارغة () {} وظيفة فارغة () {} console.log (function.prototype ، function .__ proto__) ؛ // Object {} function fmare () {} console.log (Object.prototype ، Object .__ proto__) ؛ الدالة f () {} // f {} وظيفة فارغة () {} console.log (f.prototype ، f .__ proto__) ؛قد تكون بالدوار ، دعنا نقسمه.
النموذج الأولي
تنسيق إخراج النموذج الأولي هو: اسم النموذج الأولي للمشارك
أولاً ، دعنا نلقي نظرة على أي كائن.
الكائن {} -> الكائن السابق هو اسم المنشئ ، ويمثل الكائن التالي النموذج الأولي. فيما يلي {} ، أي مثيل لكائن كائن (كائن فارغ)
ثم ن نفهم ما يعنيه. F هو اسم المنشئ ، والنموذج الأولي هو أيضًا كائن فارغ
// دعونا نلقي نظرة على المثال الذي تم إنشاؤه بواسطة المُنشئ var o = new Object () ؛ // var o = {} ؛ // كائن غير محدد {} console.log (O.Prototype ، o .__ proto__) ؛ الدالة f () {} var i = new f () ؛ // undefined f {} console.log (i.prototype ، i .__ proto__) ؛دعنا نذهب أعمق قليلاً ونحدد النموذج الأولي لـ F لنرى ماذا سيحدث؟
الدالة f () {} f.prototype.a = function () {} ؛ var i = new f () ؛ // undefined f {a: function} console.log (i.prototype ، i .__ proto__) ؛وبهذه الطريقة ، يمكننا أن نرى بوضوح أنني نشأت من F ، النموذج الأولي هو {A: Function} ، مما يعني أنه تمت إضافة الطريقة A إلى النموذج الأولي للكائن الفارغ الأصلي.
دعونا نغير الموقف ، ماذا سيحدث إذا كان النموذج الأولي الذي يغطي بالكامل و؟
الدالة f () {} f.prototype = {a: function () {}} ؛ var i = new f () ؛ // كائن غير محدد {a: function} console.log (i.prototype ، i .__ proto__) ؛مرحبًا ~ لماذا تشير هنا إلى أنني شيدت من كائن؟ لا!
نظرًا لأننا نكتب النموذج الأولي لـ F ، في الواقع ، نحدد النموذج الأولي ككائن {A: Function} ، ولكن هذا سيؤدي إلى فقدان معلومات المنشئ الأصلية وتصبح المنشئ المحدد بواسطة الكائن {a: function}.
إذن ما هو مُنشئ الكائن {a: function}؟
لأن الكائن {a: function} يتعلق فعليًا بـ
var o = {a: function () {}} // كائن جديدثم مُنشئ O هو بالطبع كائن
دعونا نصحح هذا الخطأ
الدالة f () {} f.prototype = {a: function () {}} // إعادة تحديد المنشئ الصحيح f.prototype.constructor = f ؛ var i = new f () ؛ // undefined f {a: function ، constructor: function} console.log (i.prototype ، i .__ proto__) ؛الآن يمكنك الحصول على معلومات النموذج الأولي الصحيحة مرة أخرى ~
سلسلة النموذج الأولي
ثم دعونا نلقي نظرة على ما هي سلسلة النموذج الأولي؟
ببساطة ، هو نفس علاقة الميراث (سلسلة) في OOP. ابحث عن الطبقة حسب الطبقة حتى الكائن النهائي. النمط المحدد
الشيء الأكثر أهمية هو معرفة الأشياء في JS (مثيلات). هذا بسيط ، كل شيء في JS هو الأشياء!
ثم نحتاج إلى معرفة أن أي كائن لديه نموذج أولي!
ثم دعونا نثبت ذلك:
كائن // هذه وظيفة ، الوظيفة هي كائن مثيل للدالة ، لذلك هو الكائن .__ proto__ == function.prototype // ثم النموذج الأولي للكائن ، True // هذا كائن عادي ، وبالتالي فإن مثيل الكائن ينتمي إلى protect. Object.Prototype .__ proto__ == null // function true // هذه أيضًا وظيفة ، نعم! وظيفة .__ proto__ == function.prototype // function true a () {} // هذه وظيفة مخصصة ، ولا تزال وظيفة بعد كل شيء ، هذا صحيح! a .__ proto__ == function.prototype // أي وظيفة هي مثيل للدالة ، وكذلك النموذج الأولي لـ a؟ var a = new a () a .__ proto__ == a.prototype // مثيل A تم إنشاؤه بواسطة المنشئ A ، لذلك يتم تعريف نموذج أولي لـ A بواسطة سمة النموذج الأولي للنموذج A.prototyالنموذج الأولي و __proto__
يحتوي كل كائن على __proto__ يشير إلى "النموذج الأولي" للكائن.
شيء مماثل هو أن كل وظيفة تحتوي على نموذج أولي. ما هو كائن النموذج الأولي؟
دعونا نلقي نظرة على الكود التالي ، باستخدام المُنشئ لإنشاء كائن (ما سبق هو إنشاء كائن في شكل نموذج حرفي).
دالة foo () {} ؛ var foo = new foo () ؛ console.log (foo .__ proto__) ؛فقط تخيل ، ما الذي سيشير إليه __proto__ من كائن فو؟
كائن يحتوي على سمة المنشئ؟ لا يهم إذا كنت لا تفهمها كثيرًا. اطبع سمة النموذج الأولي للدالة foo وقارنها بمعرفتك.
function foo () {} ؛ var foo = new foo () ؛ console.log (foo .__ proto __) ؛ console.log (foo.prototype) ؛ console.log (foo .__ proto__ === foo.prototype) ؛اتضح أن __proto__ للكائن الذي يخرج من جديد فقط يشير إلى النموذج الأولي للوظيفة foo.
foo .__ proto__ -> foo.prototype
ما الهدف من تصميم JS مثل هذا؟ مع استدعاء ما تم ذكره أعلاه ، في عالم JS ، لا يتم إنشاء الكائنات بناءً على فئات (قوالب) ، ولكنها مشتقة من النماذج الأولية (كائن آخر).
عندما نقوم بإجراء عمليات جديدة لإنشاء كائن جديد ، لن نتعمق في التنفيذ المحدد لعمليات جديدة ، لكننا متأكدون من شيء واحد - أي أننا نشير إلى كائن النموذج الأولي للكائن الجديد __proto__.
هذا الرمز فقط
دالة foo () {} ؛ var foo = new foo () ؛من هو foo .__ proto__ يشير إلى؟ لماذا لا يمكنك الإشارة إلى وظيفة فو نفسها؟ على الرغم من أن الوظيفة هي أيضًا كائن ، إلا أنني سأتحدث عنها بالتفصيل إذا كانت لديك الفرصة. ولكن من المؤكد أنه ليس من المناسب الإشارة إلى foo .__ proto__foo ، لأن FOO هي وظيفة مع الكثير من التعليمات البرمجية المنطقية. ككائن ، ليس له معنى لروث المعالجة المنطقية. ما يريد أن يرثه هو سمة "كائن النموذج الأولي".
لذلك ، ستقوم كل وظيفة تلقائيًا بإنشاء كائن نموذج أولي ، ويشير __proto__ للكائن الجديد من هذه الوظيفة إلى النموذج الأولي لهذه الوظيفة.
foo .__ proto__ -> foo.prototype
لخص
بعد قول الكثير ، ما زلت لم أشرح ذلك تمامًا ، لذلك من الأفضل أن أكون في الصورة السابقة. لقد أشرت إلى صور من مستخدمي الإنترنت الآخرين ، لكنني أشعر دائمًا أنني لم أشرح بوضوح ، لذلك رسمت صورة بنفسي. إذا كنت أعتقد أني جيد ، من فضلك أعجبك! (لقد بذلت قصارى جهدي لرسمها).
دعونا نلتقط هذه الصورة ونتذكر الحقائق التالية:
1. هناك سمة _proto_ في كل كائن.
لا يوجد مفهوم للفئة (العفن) في عالم JS. يتم اشتقاق الكائنات من كائن آخر (proto) ، لذلك ستكون هناك سمة _proto_ في كل كائن يشير إلى كائن النموذج الأولي الخاص به. (راجع الكائن OBJ المحدد في الشكل الحرفي في الزاوية اليسرى العلوية. يفتح مساحة لتخزين خصائص الكائن الخاصة في الذاكرة ، ويولد _proto_ يشير إلى النموذج الأولي - كائن النموذج الأولي على مستوى أعلى.)
2. كل وظيفة لها خاصية النموذج الأولي.
لماذا يسمى "مُنشئ" مُنشئ؟ لأنه يريد بناء كائن. لذا ، وفقًا للحقيقة الأولى أعلاه ، فمن الذي تفيد به سمة _proto_ من كائن جديد تم إنشاؤه؟ لا يمكنك الإشارة إلى المنشئ نفسه. على الرغم من أنه كائن أيضًا ، إلا أنك لا تريد أن يرث الكائن الجديد خصائص وطرق الوظيفة. لذلك ، سيكون لكل مُنشئ سمة نموذج أولي ، مشيرًا إلى كائن كنموذج أولي للكائن الجديد الذي تم إنشاؤه بواسطة هذا المنشئ.
3. وظائف هي أيضا كائنات.
كل وظيفة لها بعض الخصائص والأساليب الشائعة ، مثل تطبيق ()/call () ، وما إلى ذلك ، ولكن كيف يتم مورث هذه الطرق الشائعة؟ كيف يتم إنشاء الوظائف؟ فقط تخيل ، كل شيء هو كائن ، بما في ذلك الوظائف ، وهو كائن تم إنشاؤه من خلال مُنشئ. بعد ذلك ، وفقًا للحقيقة الثانية أعلاه ، سيكون لكل وظيفة أيضًا نموذجًا أوليًا يشير إلى مُنشئه. وظيفة هذا المنشئ هي وظيفة ، ويتم إنشاء جميع الوظائف في JS من الوظيفة. يتم تخزين الخصائص العامة وطرق الوظائف على وظيفة كائن النموذج الأولي.