اليوم ، كانت لدي مهمة صغيرة تتمثل في إعادة تكوين كود JS ، وقد صادفت ميزة غير متوقعة للغة ، والتي اكتسبت خلالها خبرة برمجية تزيد عن 7 سنوات في هذا يكره الكثيرون اللغة لم تفكر ولم تصادف.
بالإضافة إلى ذلك ، لم أتمكن من العثور على أي شيء على شبكة الإنترنت الروسية أو الإنجليزية ، وبالتالي قررت نشر هذا ليس طويلًا جدًا ، وليس المذكرة الأكثر إثارة للاهتمام ، ولكنها مفيدة.
من أجل عدم استخدام الثوابت foo/bar
التقليدية التي لا معنى لها ، foo/bar
مباشرة على المثال الذي كان لدينا في المشروع ، ولكن لا يزال بدون مجموعة من المنطق الداخلي وقيم مزيفة. تذكر أنه على الرغم من ذلك ، اتضح أن الأمثلة اصطناعية تمامًا.
نحن نخطو على أشعل النار
لذلك لدينا فئة:
class BaseTooltip { template = 'baseTemplate' constructor(content) { this.render(content) } render(content) { console.log('render:', content, this.template) } } const tooltip = new BaseTooltip('content')
كل شيء منطقي
ثم نحتاج إلى إنشاء نوع آخر من تلميح الأدوات يتغير فيه حقل template
class SpecialTooltip extends BaseTooltip { template = 'otherTemplate' }
وهنا انتظرني مفاجأة ، لأنه عند إنشاء كائن من نوع جديد ، يحدث ما يلي
const specialTooltip = new SpecialTooltip('otherContent')
تم BaseTooltip.prototype.template
طريقة التجسيد بالقيمة BaseTooltip.prototype.template
، وليس SpecialTooltip.prototype.template
، كما كنت أتوقع.
نحن خطوة على أشعل النار بعناية ، تصوير الفيديو
نظرًا لأن chrome DevTools لا يعرف كيفية تعيين حقول الفصل ، يجب عليك اللجوء إلى الحيل لفهم ما يحدث. باستخدام مساعد صغير ، نقوم بتسجيل لحظة التعيين إلى متغير
function logAndReturn(value) { console.log(`set property=${value}`) return value } class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content) { console.log(`call constructor with property=${this.template}`) this.render(content) } render(content) { console.log(content, this.template) } } const tooltip = new BaseTooltip('content')
وعندما نطبق هذا النهج على الصف الموروث ، فإننا نحصل على الغريب التالي:
class SpecialTooltip extends BaseTooltip { template = logAndReturn('otherTemplate') } const tooltip = new SpecialTooltip('content')
كنت متأكدًا من تهيئة حقول الكائن أولاً ، ثم يتم استدعاء باقي المنشئ. اتضح أن كل شيء أصعب.
نحن خطوة على أشعل النار ، ورسم ساق
نقوم بتعقيد الموقف من خلال إضافة معلمة أخرى إلى المُنشئ ، والتي نخصصها لكائننا
class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content, options) { this.options = logAndReturn(options)
وفقط هذه الطريقة من التصحيح (حسنا ، لا تنبيهات) قليلا
من أين جاءت هذه المشكلة؟في السابق ، تم كتابة هذا الرمز على إطار Marionette وبدا (مشروطًا) مثل هذا
const BaseTooltip = Marionette.Object.extend({ template: 'baseTemplate', initialize(content) { this.render(content) }, render(content) { console.log(content, this.template) }, }) const SpecialTooltip = BaseTooltip.extend({ template: 'otherTemplate' })
عند استخدام Marionette ، كان كل شيء يعمل كما كنت أتوقع ، أي تم استدعاء طريقة render
بقيمة template
المحددة في الفصل ، ولكن عند نسخ منطق الوحدة إلى ES6 ، خرجت المشكلة الموضحة في المقالة
عد المطبات
النتيجة:
عند إنشاء كائن من فئة موروثة ، يكون ترتيب ما يحدث كما يلي:
- تهيئة حقول الكائن من تعريف فئة موروثة
- تنفيذ مُنشئ الفئة الموروثة (بما في ذلك تهيئة الحقول داخل المُنشئ)
- فقط بعد هذا التهيئة لحقول الكائن من الفئة الحالية
- تنفيذ منشئ الفصل الحالي
نعود أشعل النار إلى الحظيرة
على وجه التحديد ، في وضعي ، يمكن حل المشكلة إما من خلال mixins أو تمرير القالب إلى المُنشئ ، ولكن عندما يتطلب منطق التطبيق تجاوز عدد كبير من الحقول ، يصبح هذا طريقة قذرة إلى حد ما.
سيكون من الجيد أن تقرأ في التعليقات اقتراحاتك حول كيفية حل المشكلة بأناقة.