ما هو النموذج الأولي
يحتوي نوع الوظيفة على نموذج أولي خاصية ، والذي يتم ترجمته مباشرة إلى النموذج الأولي. هذه الخاصية هي مؤشر ، يشير إلى كائن ، والذي يحتوي على بعض الخصائص والأساليب ، والتي ستشاركها جميع الحالات (الكائنات) التي تم إنشاؤها بواسطة الوظيفة الحالية.
بناءً على ما قيل من قبل ، يمكنك الحصول على الرمز التالي:
وظيفة person () {...} person.prototype = {Country: 'China' ، sayname: function () {...}}أولاً ، يتم إنشاء شخص مثيل من نوع الوظيفة ، ثم نموذج الشخص الأولي هو كائن ، ويشير الإعلان إلى كائن. ستتم مشاركة الخصائص والأساليب في هذا الكائن بواسطة المثيل الذي تم إنشاؤه بواسطة وظيفة الشخص الحالي. وهذا يعني:
person1 = شخص جديد () ؛ person2 = شخص جديد () ؛
يتم إنشاء Person1 و Person2 مرة أخرى من خلال مثيلات نوع وظيفة الشخص. كلاهما لديهما بلد الملكية المشتركة والطريقة sayname ، لأنهم جميعًا لديهم مؤشر (__proto__) ، مشيرًا مباشرة إلى الكائن الذي أشار إليه بواسطة profote.prototype. ومع ذلك ، يرجى ملاحظة أن مؤشر __proto__ ليس قياسيًا. يتم تعريفه فقط بواسطة متصفحات مثل Chrome و Firefox. في الواقع ، لن يتم استخدام هذه الخاصية ، ولكن لا يتم استخدامها إلا كفهم للنموذج الأولي:
فيما يتعلق باستخدام النماذج الأولية والأساليب الأخرى ، سنتحدث عنها بشكل أكثر تحديدًا لاحقًا.
إنشاء نمط كائن
بعد ذلك ، دعونا نلقي نظرة على الأساليب والأنماط الشائعة لإنشاء كائنات ، وكذلك مزاياها وعيوبها.
1. نموذج المصنع
تمامًا مثل المصنع ، يتم استخلاص عملية إنشاء كائنات ملموسة ، ويتم استخدام الوظائف لتغليف تفاصيل إنشاء كائنات ذات واجهات محددة. باستخدام وظائف بدلاً من عمل التكرار الجزئي ، يكون الرمز كما يلي:
وظيفة CreatePerson (الاسم ، العمر ، الوظيفة) {var o = new Object () ؛ O.Name = name ؛ O.AGE = العمر ؛ O.Job = Job ؛ O.SayName = function () {Alert (this.name) ؛ } ؛ return o ؛} var person1 = createPerson ("Jiangshui" ، "22" ، "Engineer") ؛هذا يخلق شخصًا ، ويحل نمط المصنع مشكلة إنشاء كائنات متكررة متكررة ، ولكنه لا يحل مشكلة التعرف على الكائن. إنه مجرد إنشاء كائن ، وبغض النظر عما إذا كان هذا الكائن يتم إنشاؤه من قالب بشري أو قالب حيوان ، فمن المستحيل التمييز بين نوع هذا الكائن.
2. وضع المنشئ
قم بإنشاء مُنشئ مخصص لتحديد الخصائص وطرق أنواع الكائنات المخصصة.
وظيفة الشخص (الاسم ، العمر ، الوظيفة) {this.name = name ؛ this.age = العمر ؛ this.job = jpb ؛ this.sayname = function () {Alert (this.name) ؛ } ؛} ؛ var person1 = شخص جديد (...) ؛3. الفرق بين وضع المنشئ ووضع المصنع:
الشخص هو كائن من نوع الوظيفة. بعد جديد ، سيستمر إنشاء كائن. ومع ذلك ، نظرًا لأن هذا الكائن الذي تم إنشاؤه حديثًا يتم تمريره في الوظيفة وتم تعيينه لهذا المؤشر ، يصبح المحتوى الذي تم تمريره في خاصية أو طريقة الكائن الذي تم إنشاؤه حديثًا.
يتم رسملة العادة الافتراضية للمصممون في الحرف الأول. يمر تنفيذ الرمز أعلاه من خلال الخطوات التالية:
في الحالات التي تم إنشاؤها بهذه الطريقة ، تحتوي جميعها على سمة مُنشأة بشكل افتراضي تشير إلى وظيفة المنشئ ، على سبيل المثال:
التنبيه (person1.constructor == شخص) ؛
لذلك ، باستخدام نمط المنشئ ، هناك تمييز النوع ، ويمكن تحديد مثيله كنوع محدد.
بالإضافة إلى ذلك ، فإن المنشئ هو وظيفة عادية. لأنك ترغب في الحصول على ردود الفعل للحصول على كائن جديد ، يمكنك استخدامه الجديد للاتصال به. إذا لم يكن الأمر كذلك ، فإن تنفيذها مباشرة مثل وظيفة طبيعية. على سبيل المثال ، إذا قمت بتنفيذ person.sayname () أعلاه ، فسوف يظهر window.name لأن الوظيفة يتم تنفيذها تحت النافذة ، لذلك هذه النقطة إلى النافذة.
وضع المنشئ معيب أيضًا. يتم إعادة إنشاء الطرق الواردة في وضع المنشئ في كل مثيل ، لذلك فإن الوظائف التي تحمل نفس الاسم في مثيلات مختلفة ليست متساوية. على سبيل المثال:
person1.sayname == person2.sayname ؛ //خطأ شنيع
وهذا يعني أن كل مثيل كائن ، والسمات والأساليب التي يتم إنشاؤها بواسطة المنشئ فريدة من نوعها ويتم نسخها. السمات فريدة من نوعها ، لأن هذا هو بالضبط الفرق بين الكائنات ، ولكن العديد من الطرق لها نفس الوظائف والرمز. إذا قمت بنسخها مرارًا وتكرارًا عدة مرات ، فسوف تضيع الموارد.
حتى نتمكن من وضع الوظيفة في الخارج ثم نشير إلى الوظيفة مع مؤشر في المنشئ. في المثال الذي تم إنشاؤه ، تخزن الطريقة مؤشرًا إلى وظيفة معينة ، مما يعني وظيفة مشتركة:
وظيفة الشخص (الاسم ، العمر) {this.name = name ؛ this.age = العمر ؛ هذا.ومع ذلك ، وبهذه الطريقة ، تصبح هذه الوظيفة وظيفة عالمية ، ولا ترتبط ارتباطًا وثيقًا بمنشئ الشخص وليس لها أي تغليف.
بعد ذلك ، يرجى الحضور إلى وضع النموذج الأولي.
وضع النموذج الأولي
تم تقديم جزء من الأساسيات حول النماذج الأولية في وقت سابق. ببساطة ، كل وظيفة لها سمة نموذجية ، تشير إلى كائن (كائن النموذج الأولي) ، ويمكن وضع بعض الخصائص أو الطرق في هذا الكائن. ثم سيكون للمثال الذي تم إنشاؤه بواسطة هذه الوظيفة سمة غير منتظمة (__proto__) تشير إلى النموذج الأولي.
من وجهة النظر هذه ، يجب أن تكون قادرًا على فهم أن الخصائص والأساليب التي تم إنشاؤها بواسطة النموذج الأولي تتقاسمها جميع الحالات.
هذا فقط يحل مشكلة مشاركة وظائف في وضع المنشئ أعلاه وفي الأمثلة. على سبيل المثال ، الكود التالي:
وظيفة person () {....} person.prototype.name = "jiangshui" ؛ person.prototype.sayname = function () {Alert (this.name) ؛} ؛ var person1 = new person () ؛ person1.sayname () ؛ // جيانغشويأو
person.prototype = {constructor: person ، الاسم: "Jiangshui" ، sayname: function () {Alert (this.name) ؛ }} ؛تغطي الطريقة الثانية كائن النموذج الأولي بأكمله ، لذلك تحتاج إلى تحديد خاصية المنشئ يدويًا ، مع الإشارة إلى وظيفة المنشئ ، وإلا فإنه سيشير إلى الكائن.
دعونا نفرز علاقتهم:
استخدم isprototypeof () لتحديد العلاقة بين الكائنات. على سبيل المثال:
person.prototype.isprototypeof (person1) ؛
عندما يقرأ الرمز خاصية معينة لكائن ، سيتم إجراء بحث. ابدأ بالكائن الحالي ، وإذا لم يكن الأمر كذلك ، فابحث عن كائن النموذج الأولي الذي أشار إليه المؤشر ، دون البحث عن المنشئ. يمكن الوصول إلى مثيل الكائن ولكن لا يمكن تجاوز قيمة كائن النموذج الأولي. إذا تم تعيين سمة تحمل نفس اسم كائن النموذج الأولي في المثيل ، تنتهي عملية البحث في المثيل دون الوصول إلى كائن النموذج الأولي ، لذلك يتم تحقيق الغرض من الكتابة فوق. لذلك ، حتى إذا تم تعيين هذه الخاصية على NULL ، فهذا يعني أن الخاصية موجودة بالفعل في المثال ، ولن يتم إلغاء الخاصية ، بحيث يمكن الوصول إلى خاصية النموذج الأولي.
لذلك ، تحتاج إلى استخدام مشغل الحذف لحذف سمات المثيل تمامًا بحيث يمكن إعادة النظر في النموذج الأولي.
النموذج الأولي ديناميكي ، ويمكن أن تنعكس أي تعديلات على كائن النموذج الأولي على الفور من المثيل. والسبب هو علاقة الارتباط الفضفاضة بين المثيل والنموذج الأولي. في كل مرة يتم استدعاء طريقة خاصية المثيل ، سيتم إجراء استعلام. إذا تغير النموذج الأولي ، فسيتغير نتيجة الاستعلام أيضًا.
بعد فهم النموذج الأولي ، يمكننا أيضًا إضافة طرق أو سمات جديدة إلى الكائن الأصلي. الأنواع المرجعية الأصلية مثل الكائن ، الصفيف ، السلسلة ، وما إلى ذلك تشبه المُنشئين أعلاه. يمكننا استخدام النموذج الأولي لتوسيع أساليبهم. على سبيل المثال:
string.prototype.startswith = function (text) {return this.indexof (text) == 0 ؛} ؛ var msg = "hello world" ؛ msg.startswith ("hello") ؛يضيف هذا الرمز طريقة startswith إلى سلسلة نوع المرجع الأصلي ، والتي تتمرير في معلمة لمعرفة ما إذا كانت السلسلة التي سيتم اختبارها تبدأ بمعلمة. نظرًا للطبيعة الديناميكية للنموذج الأولي ، تحصل جميع متغيرات نوع السلسلة على هذه الطريقة من خلال تنفيذها.
ومع ذلك ، لا ينصح هذه الطريقة. إذا كنت تستخدم الكثير من التعليمات البرمجية ، فسيؤدي ذلك إلى صعوبات في الصيانة ، والارتباك في التعليمات البرمجية ، وما إلى ذلك. بشكل عام ، سيتم ورث نوع مرجعي أصلي أولاً ، ثم يتم إنشاؤه على نوع مخصص حديثًا. فيما يتعلق بالميراث ، سنلخصه لاحقًا.
نمط النموذج الأولي ليس كليًا أيضًا. يتم مشاركة جميع السمات والأساليب في النموذج الأولي من قبل جميع الحالات ، لذلك فهي مناسبة للغاية للوظائف والوظائف الأخرى ، ولكن بالنسبة للسمات التي تحتوي على أنواع مرجعية ، ستنشأ بعض النزاعات. على سبيل المثال:
وظيفة person () {} person.prototype = {constructor: person ، الأصدقاء: ["Greg" ، "Jack"]سترى في وحدة التحكم أن هناك تومًا إضافيًا لأصدقاء Person2 ، وهذا ليس ما أريد ، ولكن عند تعريف صديقه إلى شخص 1 ، فإنه يؤثر على مثيل الشخص 2.
لذلك نحن بحاجة إلى استخدامه مع نمط النموذج الأولي ونمط المنشئ.
استخدم وضع المنشئ ووضع النموذج الأولي مجتمعًا
هذا هو النمط الأكثر استخداما. يتم استخدام المنشئ لتحديد خصائص المثيل والتخصيص عن طريق تمرير المعلمات ؛ يتم استخدام النموذج الأولي لتحديد الطرق أو السمات التي تتطلب المشاركة بين جميع الحالات. وبهذه الطريقة ، يتم تحقيق التخصيص ، وضمان المشاركة ، ويتم تجنب المشكلات.
وظيفة الشخص (الاسم ، العمر ، الوظيفة) {this.name = name ؛ this.age = العمر ؛ this.job = Job ؛ this.friends = ["Greg" ، "jack"] ؛} person.prototype = {constructor: person ، sayname: function () {Alert (this.name) ؛ }} ؛ var jiangshui = شخص جديد ("Jiangshui" ، "22" ، "Engineer") ؛أمثلة التطبيق العملي
حسنًا ، قد تفهم هنا ماهية النموذج الأولي وكيفية إنشاء كائنات ، ولكن ما هي استخدامات هذه؟ في الواقع ، كان عملي السابق هو كتابة بعض التعليمات البرمجية باستخدام jQuery ، ولم أستطع استخدام التغليف ثم إنشاء كائنات لتنفيذ وظائف ، وما إلى ذلك. ما هي استخدامات هذه؟
تستخدم طريقة التطوير هذه بشكل أساسي لتطوير المعيار والتجميع. على سبيل المثال ، فإن الوظيفة المنبثقة التي تستخدمها غالبًا ، بالطبع يمكنك لصق الرمز المنبثق ونسخه في كل مرة ، ثم تعديله واستخدامه في المشروع. يتمثل الخيار الأفضل في تغليف رمز وظيفتك المنبثقة بشكل مجردة في مثل هذا المكون ، بحيث عندما تحتاج إلى استخدام المنبثقة المنبثقة ، تحتاج فقط إلى تمرير المعلمات لإنشاء مثيل منبثقة ، ويمكنك تسميته.
كائنات النموذج الأولي وسلاسل النموذج الأولي
في JavaScript ، كل شيء هو كائن ، ولكن هناك أيضًا اختلافات في الكائنات. يمكن تقسيمه تقريبًا إلى فئتين ، وهما: الكائنات العادية (الكائن) وكائنات الوظائف (الدالة).
بشكل عام ، فإن الكائنات التي تم إنشاؤها من خلال الوظيفة الجديدة هي كائنات الوظيفة ، والكائنات الأخرى هي كائنات عادية.
إعطاء مثال:
الدالة f1 () {// toDo} var f2 = function () {// toDo} ؛ var f3 = new function ('x' ، 'console.log (x)') ؛ var o1 = {} ؛ var o2 = new Object () ؛ var o3 = new f1 () ؛ console.log (typeof f1 ، // function typeof f2 ، // function typeof f3 ، // function typeof o1 ، // object typeof o2 ، // object typeof o3 // object) ؛ >> function object Object ObjectF1 ينتمي إلى إعلان وظيفة ما. الطريقة الأكثر شيوعًا لتحديد الوظيفة هي أن F2 هي في الواقع وظيفة مجهولة. تعيين هذه الوظيفة المجهولة إلى F2 ، والتي تنتمي إلى تعبير وظيفة. F3 ليس شائعًا ، لكنه أيضًا كائن وظيفة.
الوظيفة هي كائن يأتي مع JS. عند إنشاء F1 و F2 ، ستقوم JS تلقائيًا بإنشاء هذه الكائنات من خلال وظيفة جديدة (). لذلك ، يتم إنشاء هذه الكائنات الثلاثة من خلال وظيفة جديدة ().
هناك طريقتان لإنشاء كائنات في JavaScript: الكائنات الحرفية والتعبيرات الجديدة. إن إنشاء O1 و O2 يتوافق فقط مع هاتين الطريقتين. دعونا نركز على O3. إذا كنت تستخدم أفكار Java و C# لفهمها ، فإن O3 هو كائن مثيل لـ F1 و O3 و F1 هما نفس النوع. على الأقل فكرت ذلك من قبل ، لكنها ليست ...
إذن كيف تفهمها؟ الأمر بسيط للغاية. معرفة ما إذا تم إنشاء O3 من خلال وظيفة جديدة. من الواضح لا. نظرًا لأنه ليس كائنًا دالة ، فهو كائن عادي.
بعد فهم بسيط لكائنات الوظائف والأشياء العادية ، دعونا نتعرف على النماذج الأولية وسلاسل النموذج الأولي في JavaScript:
في JS ، كلما تم إنشاء كائن وظيفة F1 ، يتم دمج بعض الخصائص في الكائن ، بما في ذلك النموذج الأولي و __proto__ ، النموذج الأولي هو كائن النموذج الأولي ، الذي يسجل بعض خصائص وطرق F1.
تجدر الإشارة إلى أن النموذج الأولي غير مرئي لـ F1 ، أي أن F1 لن يبحث عن خصائص وطرق في النموذج الأولي.
الدالة f () {} f.prototype.foo = "abc" ؛ console.log (f.foo) ؛ // غير محددإذن ، ما هو فائدة النموذج الأولي؟ في الواقع ، فإن الوظيفة الرئيسية للنموذج الأولي هي الميراث. من حيث Layman ، يتم ترك جميع الخصائص والأساليب المحددة في النموذج الأولي إلى "أحفادهم" ، بحيث يمكن للفئات الفرعية الوصول بالكامل إلى الخصائص والأساليب في النموذج الأولي.
لمعرفة كيف يترك F1 النماذج الأولية لـ "أحفاد" ، نحتاج إلى فهم سلسلة النموذج الأولي في JS. في هذا الوقت ، دخلت __proto__ في JS إلى السوق. هذا الرجل غريب ومخفي للغاية ، بحيث لا تراه في كثير من الأحيان ، ولكنه موجود في كل من الكائنات العادية وكائنات الوظائف. وظيفتها هي حفظ كائن النموذج الأولي لفئة الأصل. عندما يقوم JS بإنشاء كائن من خلال تعبير جديد ، فإنه عادة ما يعين النموذج الأولي للفئة الأصل إلى سمة __proto__ للكائن الجديد ، الذي يشكل جيلًا من الميراث ...
الدالة f () {} f.prototype.foo = "abc" ؛ var obj = new f () ؛ console.log (obj.foo) ؛ // ABCالآن نعلم أن __proto__ في OBJ يحفظ النموذج الأولي لـ F ، فما الذي يتم حفظه في __proto__ في النموذج الأولي لـ F؟ انظر الصورة التالية:
كما هو موضح في الشكل ، فإن الكائن. النموذج المخزّن في __proto__ من النمط f.protoTy ، وهناك أيضًا __proto__ في كائن الكائن. كما هو مبين في الشكل أدناه:
بعد أن يحتوي كائن OBJ على سلسلة النموذج الأولي ، عندما يتم تنفيذ OBJ.FOO ، ستجد OBJ أولاً ما إذا كان لديه السمة ، لكنه لن يجد النموذج الأولي الخاص به. عندما لا يمكن العثور على فو ، سوف يبحث OBJ بدوره على طول سلسلة النموذج الأولي ...
في المثال أعلاه ، نحدد سمة FOO على النموذج الأولي لـ F ، ثم ستجد OBJ هذه السمة على سلسلة النموذج الأولي وتنفيذها.