JavaScript هي لغة متعددة النماذج تدعم البرمجة الموجهة للكائنات وتجليد الطريقة الديناميكية - وهو مفهوم قوي يسمح بتغيير هيكل كود JavaScript أثناء تنفيذ البرنامج. هذا يوفر للمطورين فرصًا جادة ، فهو يجعل اللغة مرنة ، لكن عليك أن تدفع ثمن كل شيء. في هذه الحالة ، عليك أن تدفع بكل وضوح الكود. يتم تقديم مساهمة كبيرة في هذا السعر عن طريق
this
، حول السلوك الذي تم جمع الكثير من الأشياء التي يمكن أن تربك المبرمج.

طريقة ملزمة ديناميكية
الربط الديناميكي يسمح لك بتحديد ، أثناء تنفيذ البرنامج ، وليس أثناء التحويل البرمجي ، الطريقة التي يجب استدعاؤها عند تنفيذ أمر معين. في JavaScript ، يتم تنفيذ هذه الآلية باستخدام
this
وسلسلة النموذج الأولي. على وجه الخصوص ، يتم تحديد القيمة المحددة
this
داخل الأسلوب في وقت التشغيل ، وتختلف قواعد تحديد هذه القيمة اعتمادًا على كيفية الإعلان عن الطريقة.
هيا نلعب لعبة واحدة. أنا أسميها "ما هو مكتوب في هذا؟". هنا هو الخيار الأول لها - رمز وحدة ES6:
const a = { a: 'a' }; const obj = { getThis: () => this, getThis2 () { return this; } }; obj.getThis3 = obj.getThis.bind(obj); obj.getThis4 = obj.getThis2.bind(obj); const answers = [ obj.getThis(), obj.getThis.call(a), obj.getThis2(), obj.getThis2.call(a), obj.getThis3(), obj.getThis3.call(a), obj.getThis4(), obj.getThis4.call(a) ];
قبل قراءة المزيد ، فكر في ما سوف يندرج ضمن مجموعة الإجابات واكتب الإجابات. بعد القيام بذلك ، اختبر نفسك عن طريق
answers
صفيف
answers
باستخدام
console.log()
. هل تمكنت من "فك تشفير" قيمة
this
بشكل صحيح في كل حالة من الحالات؟
سنقوم بتحليل هذه المشكلة ، بدءًا من المثال الأول. إرجاع بناء
obj.getThis()
undefined
. لماذا؟ لا يمكن ربط وظيفة السهم هذه. تستخدم هذه الوظائف
this
من نطاق المعجم المحيط بها. تسمى الطريقة في الوحدة النمطية ES6 ، في نطاقها المعجمى ، لن يتم
undefined
. للسبب نفسه ،
undefined
إلى
obj.getThis.call(a)
. لا يمكن إعادة تعيين قيمة
this
عند العمل مع وظائف السهم حتى مع
.bind()
أو
.bind()
. هذه القيمة سوف تتوافق دائمًا مع
this
من النطاق المعجمي ، حيث توجد هذه الوظائف.
يوضح الأمر
obj.getThis2()
كيفية التعامل مع
this
عند استخدام أساليب الكائن العادية. إذا لم يكن
this
مرتبطًا بطريقة مشابهة ، بشرط أن هذه الطريقة ليست وظيفة سهم ، أي أنها تدعم
this
الربط ، تكون
this
الكلمة الأساسية مرتبطة بالكائن الذي تسمى به الطريقة باستخدام بناء جملة الوصول إلى خصائص الكائن من خلال نقطة أو استخدام الأقواس المربعة.
obj.getThis2.call(a)
هي بالفعل أصعب قليلاً لمعرفة ذلك. تسمح لك طريقة
call()
باستدعاء دالة ذات قيمة معينة من
this
، والتي يشار إليها كوسيطة اختيارية. بمعنى آخر ، في هذه الحالة ، يتم أخذ ذلك من المعلمة
obj.getThis2.call(a)
، ونتيجة لذلك ، تقوم استدعاء
obj.getThis2.call(a)
بإرجاع الكائن.
باستخدام الأمر
obj.getThis3 = obj.getThis.bind(obj);
نحن نحاول ربط
this
الطريقة ، والتي هي وظيفة السهم. كما اكتشفنا بالفعل ، لا يمكن القيام بذلك. نتيجة لذلك ،
obj.getThis3()
الاستدعاءات إلى
obj.getThis3()
و
obj.getThis3.call(a)
.
يمكن إرفاق الأساليب التي تعتبر وظائف عادية
this
، لذا تقوم
obj.getThis4()
، كما هو متوقع ، بإرجاع
obj
. استدعاء
obj.getThis4.call(a)
بإرجاع
obj
، وليس كما تتوقع ، الحقيقة هي أنه قبل استدعاء هذا الأمر ، قمنا بالفعل
obj.getThis4 = obj.getThis2.bind(obj);
هذا الأمر بـ
obj.getThis4 = obj.getThis2.bind(obj);
. نتيجة لذلك ، عند تنفيذ
obj.getThis4.call(a)
، يتم أخذ حالة الأسلوب الذي كانت عليه بعد أخذ الربط الأول في الاعتبار.
باستخدام هذا في الفصول
فيما يلي الإصدار الثاني من لعبتنا - نفس المهمة ، ولكن الآن يعتمد على الفصول الدراسية. نحن هنا نستخدم بناء الجملة للإعلان عن حقول الطبقة العامة (في الوقت الحالي ، يكون
اقتراح بناء الجملة هذا في المرحلة الثالثة من الموافقة ، وهو متاح بشكل افتراضي في Chrome ، ويمكنك استخدامه مع
@babel/plugin-proposal-class-properties
).
class Obj { getThis = () => this getThis2 () { return this; } } const obj2 = new Obj(); obj2.getThis3 = obj2.getThis.bind(obj2); obj2.getThis4 = obj2.getThis2.bind(obj2); const answers2 = [ obj2.getThis(), obj2.getThis.call(a), obj2.getThis2(), obj2.getThis2.call(a), obj2.getThis3(), obj2.getThis3.call(a), obj2.getThis4(), obj2.getThis4.call(a) ];
قبل قراءة المزيد ، فكر في الكود واكتب رؤيتك لما سوف يقع في صف
answers2
.
هل انتهيت
هنا ، جميع استدعاءات الطريقة ، باستثناء
obj2.getThis2.call(a)
، ستعود بمرجع إلى مثيل الكائن. سوف نفس المكالمة إرجاع الكائن وظائف السهم لا تزال تأخذ
this
من نطاق المعجمية. الاختلاف بين هذا المثال والمثال السابق هو الفرق في النطاق الذي يتم منه أخذ
this
.
وهي هنا نعمل مع خصائص الفصل ، والتي تحدد سلوك هذا الرمز.
الحقيقة هي أنه أثناء إعداد التعليمات البرمجية للتنفيذ ، تتم كتابة القيم على خصائص الفئات مثل هذا:
class Obj { constructor() { this.getThis = () => this; } ...
بمعنى آخر ، اتضح أنه يتم الإعلان عن وظيفة السهم داخل سياق وظيفة المنشئ. نظرًا لأننا نعمل مع فصل دراسي ، فإن الطريقة الوحيدة لإثبات ذلك هي استخدام الكلمة الأساسية
new
(إذا نسيت هذه الكلمة الرئيسية ، فسيتم عرض رسالة خطأ).
تتمثل أهم المهام التي تم حلها بواسطة الكلمة الأساسية
new
في إنشاء مثيل جديد للكائن ولربط
this
بالمنشئ. هذه الميزة ، مع مراعاة ما تحدثنا عنه بالفعل في القسم السابق ، ينبغي أن تساعدك على فهم ما يحدث.
النتائج
هل أكملت المهام الموضحة في هذه المقالة؟ إن الفهم الجيد لكيفية تصرف
this
الكلمة الرئيسية في JavaScript سيوفر لك الكثير من الوقت عند تصحيح الأخطاء ، عند البحث عن أسباب غير واضحة للأخطاء الغامضة. إذا أجبت على بعض الأسئلة بشكل غير صحيح ، فهذا يعني أنه سيكون من المفيد لك التدرب.
قم بتجربة نموذج التعليمات البرمجية ، ثم حاول مرة أخرى ، وهكذا ، حتى تتمكن من الإجابة على جميع الأسئلة بشكل صحيح. بعد أن تكتشف ذلك بنفسك ، ابحث عن شخص ما على استعداد للاستماع إليك وأخبره لماذا تعيد طرق المهام ما يعيدونه بالضبط.
إذا كان كل هذا يبدو لك أكثر تعقيدًا مما توقعت ، فاعلم أنك لست وحدك في هذا. لقد اختبرت عددًا كبيرًا من المطورين لمعرفة ميزات
this
، وأعتقد أن واحدًا منهم فقط كان دقيقًا تمامًا في جميع إجاباتهم.
بدأ هذا النظام الفرعي للغة ، الذي بدا في البداية مثل البحث الديناميكي عن الأساليب التي يمكن أن تتأثر باستخدام
.bind()
أو
.apply()
أو
.apply()
، في الظهور بمزيد من التعقيد بعد ظهور وظائف وفئات السهم.
على ما يبدو ، سيكون من المفيد ملاحظة الميزات الرئيسية للفئات ووظائف السهم من حيث استخدام
this
. تذكر أن وظائف السهم تستخدم دائمًا
this
من نطاقها المعجمي ، وأن
this
في الفصول ، في الواقع ، مرتبطة بوظيفة مُنشئ الفصل. وإذا شعرت يومًا بأنك لا تعرف بالضبط ما الذي يشير إليه
this
، فاستخدم مصحح الأخطاء للتحقق من افتراضاتك حول هذا الأمر.
تذكر أيضًا أنه يمكنك عمل الكثير في JavaScript دون استخدام
this
في التعليمات البرمجية الخاصة بك. تخبرني التجربة أنه يمكن إعادة كتابة أي كود JS تقريبًا في شكل وظائف خالصة تقبل جميع الوسائط التي تعمل معها ، في شكل قائمة معلمات محددة بوضوح (يمكن تفسير ذلك كمعلمة محددة ضمنيًا مع حالة قابلة للتغيير). المنطق الوارد في الوظائف البحتة حتمية ، مما يحسن قابليتها للاختبار. ليس لهذه الوظائف آثار جانبية ، مما يعني أنه عند التعامل معها ، على عكس التلاعب
this
، فمن غير المرجح أن "تكسر" أي شيء خارجها. كلما غيرت
this
، فإنك تواجه مشكلة محتملة ، وهي أن شيئًا يعتمد على
this
قد يتوقف عن العمل بشكل صحيح.
على الرغم مما ذكر أعلاه ، تجدر الإشارة إلى أن
this
مفهوم مفيد. على سبيل المثال ، يمكن تطبيقه من أجل تنظيم مشاركة طريقة معينة من خلال العديد من الكائنات. حتى في البرمجة الوظيفية ، يمكن أن يكون
this
مفيدًا للاتصال بالطرق الأخرى من طريقة واحدة للكائن ، مما يسمح لك بإنشاء شيء جديد بناءً على البنيات الموجودة.

