هذه المقالة لفهم النصوص القديمة
المعلومات الواردة في هذه المقالة مفيدة لفهم البرامج النصية القديمة.
هذه ليست الطريقة التي نكتب بها الكود الجديد.
في الفصل الأول عن المتغيرات ذكرنا ثلاث طرق لإعلان المتغيرات:
let
const
var
إعلان var
مشابه لـ let
. يمكننا في أغلب الأحيان استبدال let
بـ var
أو العكس ونتوقع أن تسير الأمور على ما يرام:
رسالة فار = "مرحبًا"; تنبيه (رسالة)؛ // أهلاً
لكن var
داخليًا هو وحش مختلف تمامًا، نشأ من العصور القديمة جدًا. لا يتم استخدامه بشكل عام في النصوص الحديثة، ولكنه لا يزال كامنًا في النصوص القديمة.
إذا كنت لا تخطط لتلبية مثل هذه النصوص، فيمكنك تخطي هذا الفصل أو تأجيله.
من ناحية أخرى، من المهم فهم الاختلافات عند ترحيل البرامج النصية القديمة من var
إلى let
لتجنب الأخطاء الفردية.
المتغيرات التي تم الإعلان عنها باستخدام var
، تكون إما ذات نطاق وظيفي أو ذات نطاق عالمي. أنها مرئية من خلال الكتل.
على سبيل المثال:
إذا (صحيح) { اختبار فار = صحيح؛ // استخدم "var" بدلاً من "let" } تنبيه (اختبار)؛ // صحيح، المتغير يعيش بعد if
بما أن var
يتجاهل كتل التعليمات البرمجية، فقد حصلنا على test
متغير عام.
إذا استخدمنا let test
بدلاً من var test
، فسيكون المتغير مرئيًا فقط في if
:
إذا (صحيح) { دع الاختبار = صحيح؛ // استخدم "السماح" } تنبيه (اختبار)؛ // خطأ مرجعي: لم يتم تعريف الاختبار
نفس الشيء بالنسبة للحلقات: لا يمكن أن يكون var
عبارة عن كتلة أو حلقة محلية:
لـ (var i = 0; i < 10; i++) { فار واحد = 1؛ // ... } تنبيه (ط)؛ // 10، يظهر "i" بعد الحلقة، وهو متغير عام تنبيه (واحد)؛ // 1، يظهر "واحد" بعد الحلقة، وهو متغير عام
إذا كانت كتلة التعليمات البرمجية موجودة داخل دالة، فسيصبح var
متغيرًا على مستوى الوظيفة:
الدالة sayHi() { إذا (صحيح) { عبارة var = "مرحبًا"; } تنبيه(عبارة); // يعمل } sayHi(); تنبيه(عبارة); // خطأ مرجعي: لم يتم تعريف العبارة
كما نرى، var
يخترق if
أو for
أو كتل التعليمات البرمجية الأخرى. هذا لأنه منذ وقت طويل في جافا سكريبت، لم يكن للكتل أي بيئات معجمية، و var
هو من بقايا ذلك.
إذا أعلنا عن نفس المتغير مع let
مرتين في نفس النطاق، فهذا خطأ:
السماح للمستخدم؛ السماح للمستخدم؛ // SyntaxError: تم الإعلان عن "المستخدم" بالفعل
باستخدام var
، يمكننا إعادة تعريف المتغير لأي عدد من المرات. إذا استخدمنا var
مع متغير مُعلن عنه بالفعل، فسيتم تجاهله:
فار المستخدم = "بيت"; فار المستخدم = "جون"; // هذا "var" لا يفعل شيئًا (تم الإعلان عنه بالفعل) // ... لا يؤدي إلى حدوث خطأ تنبيه (المستخدم)؛ // جون
تتم معالجة إعلانات var
عند بدء تشغيل الوظيفة (أو عند بدء تشغيل البرنامج النصي للعناصر العالمية).
بمعنى آخر، يتم تعريف متغيرات var
من بداية الدالة، بغض النظر عن مكان التعريف (على افتراض أن التعريف ليس في الدالة المتداخلة).
لذلك هذا الرمز:
الدالة sayHi() { عبارة = "مرحبًا"; تنبيه(عبارة); عبارة فار؛ } sayHi();
…هل هو نفس هذا من الناحية الفنية ( var phrase
المنقولة أعلاه):
الدالة sayHi() { عبارة فار؛ عبارة = "مرحبًا"; تنبيه(عبارة); } sayHi();
…أو حتى على هذا النحو (تذكر أنه يتم تجاهل كتل التعليمات البرمجية):
الدالة sayHi() { عبارة = "مرحبًا"; // (*) إذا (خطأ) { عبارة فار؛ } تنبيه(عبارة); } sayHi();
يطلق الناس أيضًا على هذا السلوك اسم "الرفع" (رفع)، لأن جميع var
"مرفوعة" (مرفوعة) إلى أعلى الوظيفة.
لذلك في المثال أعلاه، if (false)
أبدًا، لكن هذا لا يهم. تتم معالجة var
بداخلها في بداية الوظيفة، لذلك في لحظة (*)
المتغير موجود.
يتم رفع الإعلانات، ولكن المهام ليست كذلك.
من الأفضل توضيح ذلك بمثال:
الدالة sayHi() { تنبيه(عبارة); عبارة var = "مرحبًا"; } sayHi();
يحتوي السطر var phrase = "Hello"
على إجراءين:
إعلان متغير var
مهمة متغيرة =
.
تتم معالجة الإعلان في بداية تنفيذ الوظيفة ("الرفع")، ولكن التعيين يعمل دائمًا في المكان الذي يظهر فيه. لذا فإن الكود يعمل بشكل أساسي مثل هذا:
الدالة sayHi() { عبارة فار؛ // يعمل الإعلان في البداية ... تنبيه(عبارة); // غير محدد عبارة = "مرحبًا"; // ... المهمة - عندما يصل التنفيذ إليها. } sayHi();
نظرًا لأن جميع إعلانات var
تتم معالجتها عند بدء الوظيفة، فيمكننا الرجوع إليها في أي مكان. لكن المتغيرات غير محددة حتى التعيينات.
في كلا المثالين أعلاه، يتم تشغيل alert
بدون خطأ، لأن phrase
المتغيرة موجودة. ولكن لم يتم تعيين قيمتها بعد، لذلك تظهر undefined
.
في الماضي، نظرًا لوجود var
فقط، ولم يكن له رؤية على مستوى الكتلة، اخترع المبرمجون طريقة لمحاكاته. ما فعلوه كان يسمى "تعبيرات الوظائف التي يتم استدعاؤها فورًا" (المختصرة باسم IIFE).
وهذا ليس شيئًا يجب أن نستخدمه هذه الأيام، ولكن يمكنك العثور عليه في النصوص القديمة.
يبدو IIFE كما يلي:
(وظيفة() { فار الرسالة = "مرحبا"; تنبيه (رسالة)؛ // مرحبًا })();
هنا، يتم إنشاء تعبير دالة ويتم استدعاؤه على الفور. لذلك يتم تنفيذ الكود على الفور وله متغيراته الخاصة.
يتم تغليف تعبير الوظيفة بين قوسين (function {...})
، لأنه عندما يواجه محرك JavaScript "function"
في الكود الرئيسي، فإنه يفهمها على أنها بداية لإعلان الوظيفة. لكن يجب أن يكون لإعلان الدالة اسم، لذا فإن هذا النوع من التعليمات البرمجية سيعطي خطأ:
// يحاول الإعلان عن دالة واستدعائها على الفور function() { // <-- SyntaxError: تتطلب عبارات الدالة اسم دالة فار الرسالة = "مرحبا"; تنبيه (رسالة)؛ // مرحبًا }();
حتى لو قلنا: "حسنًا، دعنا نضيف اسمًا"، فلن ينجح ذلك، لأن JavaScript لا تسمح باستدعاء إعلانات الوظائف على الفور:
// خطأ في بناء الجملة بسبب الأقواس أدناه وظيفة الذهاب () { }(); // <-- لا يمكن استدعاء إعلان الوظيفة على الفور
لذا، فإن الأقواس حول الوظيفة هي خدعة لإظهار جافا سكريبت أن الوظيفة تم إنشاؤها في سياق تعبير آخر، وبالتالي فهي تعبير دالة: لا تحتاج إلى اسم ويمكن استدعاؤها على الفور.
توجد طرق أخرى إلى جانب الأقواس لإخبار JavaScript بأننا نعني تعبيرًا وظيفيًا:
// طرق إنشاء IIFE (وظيفة() { تنبيه("الأقواس حول الدالة"); })(); (وظيفة() { تنبيه ("الأقواس حول كل شيء")؛ }()); !وظيفة() { تنبيه("عامل Bitwise NOT يبدأ التعبير"); }(); + وظيفة () { تنبيه("Unary plus يبدأ التعبير"); }();
في جميع الحالات المذكورة أعلاه، نعلن عن التعبير الوظيفي ونقوم بتشغيله على الفور. دعونا نلاحظ مرة أخرى: في الوقت الحاضر لا يوجد سبب لكتابة مثل هذا الكود.
هناك اختلافان رئيسيان بين var
مقارنة بـ let/const
:
لا تحتوي متغيرات var
على نطاق كتلة، ويتم تحديد نطاق رؤيتها إلى الوظيفة الحالية، أو عمومية، إذا تم الإعلان عنها خارج الوظيفة.
تتم معالجة إعلانات var
عند بدء الوظيفة (بدء البرنامج النصي للعناصر العالمية).
هناك اختلاف بسيط آخر يتعلق بالكائن الشامل، والذي سنغطيه في الفصل التالي.
هذه الاختلافات تجعل var
أسوأ let
معظم الأوقات. تعد المتغيرات على مستوى الكتلة أمرًا رائعًا. لهذا السبب، تم تقديم let
في المعيار منذ فترة طويلة، وهو الآن طريقة رئيسية (جنبًا إلى جنب مع const
) للإعلان عن متغير.