في الآونة الأخيرة ، أعيد قراءة "JavaScript Advanced Programming 3" وأشعر أنه يجب علي كتابة بعض المدونات لتسجيل بعض المعرفة التي تعلمتها ، وإلا سأنسى ذلك. ما أريد تلخيصه اليوم هو بيئة تنفيذ JS ونطاقها.
أولاً ، دعنا نتحدث عن بيئة التنفيذ
1. بيئة التنفيذ
يحدد المفهوم في الكتاب ، بيئة التنفيذ البيانات الأخرى التي يمكن للمتغيرات أو الوظائف الوصول إليها ، وتحدد سلوكياتها الخاصة. كل بيئة تنفيذ لديها كائن متغير مرتبط به. يتم تخزين جميع المتغيرات والوظائف المحددة في البيئة في هذا الكائن. على الرغم من أننا لا نستطيع الوصول إلى هذا الكائن عند كتابة التعليمات البرمجية ، فإن المحلل سوف يستخدمه في الخلفية عند معالجة البيانات.
بيئة التنفيذ هي مفهوم ، وهي آلية تحدد ما إذا كان المتغير أو الدالة لديه إذن للوصول إلى البيانات الأخرى
في JavaScript ، يتم تقسيم رمز JavaScript القابل للتنفيذ إلى ثلاثة أنواع:
1. الكود العالمي ، أي الكود العالمي غير الموجود في أي وظيفة ، مثل: ملف JS ، رمز JS مضمن في صفحات HTML ، إلخ.
2. رمز eval ، أي رمز JS الذي يتم تنفيذه ديناميكيًا باستخدام وظيفة eval ().
3. رمز الوظيفة ، أي رمز JS Body في الوظائف المعرفة من قبل المستخدم.
تخطي رمز التقييم وتحدث فقط عن بيئة التنفيذ العالمية وبيئة تنفيذ الوظائف.
1. البيئة العالمية:
البيئة العالمية هي أكثر بيئة التنفيذ المحيطية. تعتبر بيئة التنفيذ العالمية كائن نافذة. لذلك ، يتم إنشاء جميع المتغيرات والوظائف العالمية كخصائص وطرق كائنات النوافذ. عندما يتم تحميل الرمز في المتصفح ، يتم إنشاء بيئة التنفيذ العالمية (يتم تدمير بيئة التنفيذ العالمية فقط عندما نغلق صفحة الويب أو المتصفح). على سبيل المثال ، في الصفحة ، قم بإنشاء بيئة تنفيذ عالمية عند تحميل رمز JS لأول مرة.
هذا هو السبب في أن الإغلاق لديها عيوب تسرب الذاكرة. لأن الوظائف الخارجية في عمليات الإغلاق يتم التعامل معها كبيئة عالمية. لذلك لن يتم تدميره وسيتم الاحتفاظ به في الذاكرة.
2. بيئة تنفيذ الوظيفة
كل وظيفة لها بيئة التنفيذ الخاصة بها. عندما يدخل التنفيذ وظيفة ، سيتم دفع بيئة تنفيذ الوظيفة إلى أعلى مكدس بيئة التنفيذ والحصول على حقوق التنفيذ. عند تنفيذ هذه الوظيفة ، يتم حذف بيئة التنفيذ الخاصة بها من الجزء العلوي من المكدس ويتم إرجاع حق التنفيذ إلى بيئة التنفيذ السابقة. هذا هو تدفق التنفيذ في برنامج ECMAScript.
يمكن أيضًا تفسيره بهذه الطريقة: عند استدعاء وظيفة JavaScript ، ستدخل الوظيفة بيئة التنفيذ المقابلة للوظيفة. إذا تم استدعاء وظيفة أخرى ، يتم إنشاء بيئة تنفيذ جديدة ، وعملية التنفيذ في تلك البيئة أثناء مكالمة الوظيفة. عند إرجاع الدالة المسمى ، تعود عملية التنفيذ إلى بيئة التنفيذ الأصلية. لذلك ، فإن تشغيل رمز JavaScript يشكل مكدسًا لبيئة التنفيذ.
عندما يتم استدعاء وظيفة ، يتم إنشاء البيئة المحلية للوظيفة (بعد تنفيذ الكود في الوظيفة ، يتم تدمير البيئة ، ويتم تدمير جميع المتغيرات وتعريفات الوظائف المخزنة فيها).
2-1 فترة التعريف
عندما يتم تعريف وظيفة ، سيتم إنشاء سمة [[النطاق]]. هذا الكائن يتوافق مع قائمة الكائنات. لا يمكن الوصول إلى الكائنات الموجودة في القائمة داخليًا إلا بواسطة JavaScript ولا يمكن الوصول إليها من خلال بناء الجملة.
(النطاق يعني النطاق.)
نحدد وظيفة عالمية A ، ثم تنشئ الدالة A سمة [[النطاق]]. في هذا الوقت ، [[النطاق]] يحتوي فقط على الكائن العالمي [الكائن العالمي].
إذا حددنا وظيفة B داخل A ، فستقوم الوظيفة B أيضًا بإنشاء سمة [[Scope]]. تحتوي سمة B [[Scope]] على كائنين ، أحدهما هو كائن تنشيط الكائن النشط للكائن A النشط والآخر هو الكائن العالمي. كائن A النشط في المقدمة والكائن العالمي في الخلف.
باختصار ، يكون ترتيب قائمة الكائنات في خاصية [النطاق] للدالة هو كائن التنشيط للطبقة السابقة للوظيفة ، ثم الطبقة العليا ، وصولاً إلى الكائن العالمي الخارجي.
فيما يلي رمز العينة: A لديه نطاق واحد فقط ، B له نطاقان
// وظيفة الوظيفة الخارجية A () {var somevar ؛ // وظيفة الدالة الداخلية b () {var somevar ؛ }}2-2 فترة التنفيذ
عند تنفيذ وظيفة ، فإنها تدخل بيئة تنفيذ الوظيفة. أولاً ، إنه ينشئ كائنه النشط الخاص به [كائن التنشيط] (يحتوي هذا الكائن على تعريف هذا ، والوسائط ، والمتغيرات المحلية (بما في ذلك المعلمات المسماة) وسلسلة نطاق لكائن متغير. ثم ، انسخ نطاق بيئة التنفيذ في سلسلة [Scope]] في الترتيب ، وأخيراً دفع الكائن النشط إلى الجزء العلوي من [سلسلة النطاق]]. الكائنات التي لديها إذن للوصول إلى بيئة التنفيذ.
// الخطوة الأولى هي إنشاء بيئة التنفيذ العالمية. سياق التنفيذ العالمي وكائنات النشاط العالمي. // تحديد Global [[Scope]] ، الذي يحتوي فقط على كائنات النوافذ // مسح متغيرات التعريف العالمي وكائنات الوظائف: اللون 【غير محدد】 ، ChangeColor 【FD يخلق changeColor [[Scope]] ، والذي يحتوي فقط على كائنات النشاط] ، والتي تتم إضافتها إلى النافذة ، وبالتالي فإن المتغيرات العالمية والوظيفة العالمية محددة على أنها Properies. // تم تعريف البرنامج حتى يمكن تنفيذ ChangeColor () في أي مكان في بيئة التنفيذ هذه. تم تحديد اللون أيضًا ، لكن قيمته غير محددة // الخطوة الثانية هي تعيين اللون "الأزرق" var color = "blue" ؛ Alloycolor 【غير محددة】 و swapcolors 【FD تنشئ swapcolors [[Scope]] وإضافة الكائنات النشطة والكائنات النشطة العالمية】 إلى الكائنات النشطة ، وأيضًا إضافة وسيطات و // هذا / / الكائنات النشطة تدفع إلى سلسلة النطاق // قد تم تعريف البرنامج حتى يتم تنفيذ swapcolors () في أي مكان في التنفيذ. تم تعريف AloneColor ، ولكن قيمته غير محددة // التخصيص الخامس للألوان الأخرى "Red" var OsherColor = "Red" ؛ // لا يتطلب الأمر تعيينًا ، فهو يشير إلى وظائفه الخاصة swapcolors () {// الخطوة 7 أدخل بيئة التنفيذ الخاصة بـ swapcolors وإنشاء كائنها النشط // copy swapcolors '[[scope]] سيتم العثور على قيمة تعيين TempColor لألوان أخرى ، وألوان أخرى ولون على طول سلسلة النطاق ، وتستمر في تنفيذ var tempcolor = OsherColor ؛ analycolor = اللون ؛ اللون = tempcolor ؛ }.2-3 معرف الوصول:
عند مواجهة معرف أثناء تنفيذ رمز JS ، فإنه سيبحث في سلسلة نطاق سياق التنفيذ (سياق التنفيذ) بناءً على اسم المعرف. بدءًا من الكائن الأول لسلسلة النطاق (كائن تنشيط الوظيفة) ، إذا لم يتم العثور عليه ، فابحث عن الكائن التالي في سلسلة النطاق ، وكرر حتى يتم العثور على تعريف المعرف. إذا لم يتم العثور على الكائن الأخير في النطاق بعد البحث عن البحث ، أي الكائن العالمي (الكائن العالمي) ، سيتم طرح خطأ ، مما يدفع غير محدد.
2. سلسلة النطاق/النطاق (سلسلة النطاق/النطاق)
عندما يتم تنفيذ الكود في بيئة ، يتم إنشاء سلسلة نطاق. الغرض من سلسلة النطاق هو ضمان الوصول المنظم إلى جميع المتغيرات والوظائف التي لديها إذن للوصول إلى بيئة التنفيذ. سلسلة النطاق بأكملها عبارة عن قائمة مرتبطة بواسطة كائنات متغيرة في مواقع تنفيذ مختلفة وفقًا للقواعد. الواجهة الأمامية لسلسلة النطاق هي دائمًا الكائن المتغير في البيئة حيث يوجد الكود الذي يتم تنفيذه حاليًا.
إذا كانت هذه البيئة وظيفة ، يتم استخدام كائن التنشيط الخاص به ككائن متغير. يحتوي الكائن النشط فقط على متغير واحد في البداية ، وهو كائن الوسائط داخل الوظيفة. يأتي الكائن المتغير التالي في سلسلة النطاق من بيئة إدراج الوظيفة ، ويأتي الكائن المتغير التالي من بيئة التضمين التالية. وبهذه الطريقة ، تستمر في بيئة التنفيذ العالمية ، والكائن المتغير لبيئة التنفيذ العالمية هو دائمًا الكائن الأخير في سلسلة النطاق.
كما هو مبين في الشكل:
أمثلة في الكتاب:
var color = "Blue" ؛ دالة changeColor () {var anallecolor = "red" ؛ دالة swapcolors () {var tempcolor = analleColor ؛ analycolor = اللون ؛ اللون = tempcolor ؛ // todo something} swapcolors () ؛} changeColor () ؛ // لا يمكن الوصول إلى tempcolor و anocolor هنا ؛ ولكن يمكن الوصول إلى اللون ؛ تنبيه ("اللون الآن"+لون) ؛من خلال التحليل أعلاه ، يمكننا أن نعلم أن البيئة الداخلية يمكنها الوصول إلى جميع البيئات الخارجية من خلال سلاسل النطاق ، لكن البيئة الخارجية لا يمكنها الوصول إلى أي متغيرات ووظائف في البيئة الداخلية.
هذه البيئات خطية ومنظمة. يمكن لكل بيئة البحث عن سلاسل النطاق لأعلى للاستعلام عن متغيرات وأسماء الوظائف ؛ ومع ذلك ، لا يمكن لأي بيئة إدخال بيئة تنفيذ أخرى عن طريق البحث عن سلاسل النطاق لأسفل.
بالنسبة لوظيفة SwapColor () في المثال أعلاه ، تتضمن سلسلة نطاقها: كائن متغير SwapColor () ، كائن متغير changeColor () ، والكائن العالمي. تبدأ البيئة المحلية لـ SwapColor () في البحث عن المتغيرات وأسماء الوظائف في كائنها المتغير. إذا كان لا يمكن العثور عليها ، فابحث عن سلسلة نطاق ChangeColor للأعلى. . . . . وهلم جرا. ومع ذلك ، لا يمكن لوظيفة ChangeColor () الوصول إلى المتغيرات في SwapColor
الوحي: حاول استخدام المتغيرات المحلية لتقليل وقت البحث
1. لا يوجد نطاق على مستوى الكتلة
على عكس C و C ++ و Java ، ليس لدى JavaScript نطاق مستوى الكتلة. انظر إلى الكود التالي:
if (true) {var myvar = "Zhang San" ؛ } تنبيه (myvar) ؛ // Zhang Sanإذا كان هناك نطاق على مستوى الكتلة ، فلا يمكن الوصول إلى Myvar من الخارج. انظر إلى ما يلي
لـ (var i = 0 ؛ i <10 ؛ i ++) {console.log (i)} Alert (i) ؛ // 10بالنسبة لللغات ذات النطاق على مستوى الكتلة ، مثل كود Java أو C# ، فإنني متغير تهيئته ، ولا يمكن الوصول إليه في الخارج. لأنني موجود فقط في وزن الحلقة ، بعد تشغيل الحلقة ، يتم تدمير جميع المتغيرات في لـ for. هذا ليس هو الحال في جافا سكريبت. سيتم إضافة الإعلان المتغير في لبيئة التنفيذ الحالية (فيما يلي بيئة التنفيذ العالمية). لذلك ، بعد اكتمال حلقة For ، لا يزال المتغير الذي لا يزال موجودًا في بيئة التنفيذ خارج الحلقة. لذلك ، سيتم الإخراج 10.
2. إعلان المتغيرات
عندما يتم الإعلان عن متغير باستخدام VAR ، سيتم إضافة هذا المتغير تلقائيًا إلى أقرب بيئة متاحة. بالنسبة للداخل من الوظيفة ، فإن أقرب بيئة هي المتغيرات المحلية للوظيفة. إذا لم يتم تهيئة المتغير ، يتم إضافة المتغير تلقائيًا إلى الوظيفة العالمية.
الرمز كما يلي:
var name = "Xiao Ming" ؛ وظيفة getName () {Alert (name) ؛ // 'undefined' var name = 'xiao huang' ؛ تنبيه (اسم) ؛ // Xiao Huang} getName ()لماذا الاسم الأول غير محدد؟ وذلك لأن محلل JavaScript يدخل بيئة تنفيذ الوظائف ومسح VAR والوظيفة أولاً.
إنه يعادل تعزيز إعلان VAR أو الوظيفة [إعلان الوظيفة] إلى أعلى بيئة التنفيذ.
بمعنى آخر ، عند إدخال وظيفة getName الخاصة بنا ، تجد آلية بحث المعرف VAR ، والاسم هو الاسم المتغير المحلي ، وليس الاسم العالمي ، لأنه يتم ترقية الاسم الموجود في الوظيفة إلى الأعلى.
سيتم تحليل الرمز أعلاه على النحو التالي:
var name = "Xiao Ming" ؛ وظيفة getName () {var name ؛ تنبيه (اسم) ؛ // 'undefined' var name = 'xiao huang' ؛ تنبيه (اسم) ؛ // Xiao Huang} getName ()تمديد سلسلة النطاق:
على الرغم من وجود نوعين فقط من بيئات التنفيذ - النطاق العالمي والنطاق الوظيفي ، لا يزال من الممكن تمديد سلسلة النطاق بطريقة ما. لأن بعض العبارات يمكن أن تضيف كائن متغير مؤقت إلى أعلى سلسلة النطاق.
هناك حالتان يحدثان فيه:
1. كتلة الصيد من بيان المحاولة ؛
2. مع البيان.
ما سبق هو كل شيء عن هذا المقال. آمل أن يكون من المفيد للجميع أن يتعلموا وفهم بيئة تنفيذ JavaScript ونطاقها.