ذكرنا في أوائل الفصول حين تكلمنا عن المتغيرات - ذكرنا ثلاث طرائق للتصريح عنها:
-
let
-
const
-
var
تتصرّف كلا الإفادتين let
وconst
بذات الطريقة (بالمقايسة مع البيئات المُعجمية).
بينما var
فهو وحش آخر مختلف جذريًا ويعود في أصله إلى قرون سحيقة. لا نستعمله عادةً في السكربتات الحديثة ولكنّك ستجده حتمًا خلف إحدى صخور السكربتات القديمة.
لو لم ترغب بالتعرّف على هذه السكربتات فيمكنك تخطّي هذا الفصل أو تأجيله لوقت لاحق. ولكن لا تنسَ احتمالية ندمك لاحقًا فيغدر بك هذا الوحش.
من أول وهلة نرى بأنّ تصرّف var
يشابه تصرّف let
، أي أنّه يُصرّح (مثل الثاني) عن متغير:
function sayHi() { // متغير محلي، استعملنا «var» بدل «let» var phrase = "Hello"; alert(phrase); // Hello } sayHi(); alert(phrase); // خطأ، phrase غير معرّف
ولكن… ما خفي كان أعظم. إليك الفروق.
ليس لإفادة var نطاقًا كتليًا
حين نصرّح عن المتغيرات باستعمال var
نكون جعلناها معروفة للدالة كاملةً (لو كانت في دالة) أو عمومية في السكربت. يمكنك أن ترى تلك المتغيرات إن اخترقت «جدران» الكُتل.
مثال:
if (true) { var test = true; // نستعمل «var» بدل «let» } alert(test); // الناتج true، أي أنّ المتغير «حيّ يُرزق» بعد إفادة if
تجاهل var
كتل الشيفرة، وبهذا صار متغير test
عموميًا.
لو استعملنا let test
بدل var test
فسيكون المتغير ظاهرًا لباقي الشيفرة داخل إفادة if
فقط لا غير:
if (true) { let test = true; // نستعمل «let» } alert(test); // خطأ: لم يُعرّف عن test
يسري الأمر ذاته على الحلقات فلا يمكن أن يكون var
محليًا حسب الكتلة أو حسب الحلقة:
for (var i = 0; i < 10; i++) { // ... } alert(i); // 10، ظهر «i» بعد الحلقة فهو متغير عمومي
لو كتبت كتلة شيفرة في دالة فسيصير var
متغيرًا على مستوى الدالة كاملةً.
function sayHi() { if (true) { var phrase = "Hello"; } alert(phrase); // يمكننا فعل هذا } sayHi(); alert(phrase); // خطأ: phrase غير معرّف (طالِع مِعراض المطوّر)
كما نرى فإفادة var
تخترق كُتل if
وfor
وغيرها من كُتل شيفرة. يعزو ذلك إلى أنّه في الزمن الماضي الجميل لم تكن لكُتل جافاسكربت بيئات مُعجمية. وvar
إحدى آثار ذلك الزمن.
تعالج التصريحات باستعمال var
عند بدء الدالة
تُعالج التصريحات باستعمال var
متى ما بدأت الدالة (أو بدأ السكربت، للمتغيرات العمومية).
أي أنّ متغيرات var
تُعرّف من بداية الدالة مهما كان مكان تعريفها (هذا لو لم يكن التعريف في دالة متداخلة أخرى).
يعني ذلك أنّ هذه الشيفرة:
function sayHi() { phrase = "Hello"; alert(phrase); var phrase; } sayHi();
متطابقة تقنيًا مع هذه (بتحريك var phrase
إلى أعلى):
function sayHi() { var phrase; phrase = "Hello"; alert(phrase); } sayHi();
أو حتى هذه (لا تنسَ بأنّ كُتل الشيفرات مُهملة):
function sayHi() { phrase = "Hello"; // (*) if (false) { var phrase; } alert(phrase); } sayHi();
يدعو الناس هذا السلوك بسلوك «الطفو» hoisting (أو الرفع) إذ أنّ متغيرات var
«تطفو» إلى أعلى الدالة (أو ترتفع إلى أعلاها).
أي أنّه في المثال أعلاه، الفرع if (false)
من الإفادة لا يعمل قط ولكن هذا ليس بمهم، إذ أنّ var
داخله سيُعالج في بداية الدالة، وحين تصل عملية التنفيذ إلى (*)
سيكون المتغير موجودًا لا محالة.
التصريحات تطفو صحيح، ولكنّ ليس عبارات الإسناد.
الأفضل لو نمثّل ذلك في هذا المثال:
function sayHi() { alert(phrase); var phrase = "Hello"; } sayHi();
في السطر var phrase = "Hello"
إجراءان اثنان:
-
التصريح عن المتغير باستعمال
var
-
إسناد قيمة للمتغير باستعمال
=
.
يتعامل المحرّك مع التصريحات متى بدء تنفيذ الدالة (إذ التصريحات تطفو)، ولكنّ عبارة الإسناد لا تعمل إلّا حيثما ظهرت، فقط. إذًا فالشيفرة تعمل بهذا النحو فعليًا:
function sayHi() { var phrase; // بادئ ذي بدء، يعمل التصريح... alert(phrase); // غير معرّف phrase = "Hello"; // ...هنا. } sayHi();
يُعالج المحرّك التصريحات var
حين تبدأ الدوال، وبهذا يمكننا الإشارة إليها أينما أردنا في الشيفرة. ولكن انتبه فالمتغيرات غير معرّفة حتى تُسند إليها قيم.
في الأمثلة أعلاه عمل التابِع alert
دون أيّ أخطاء إذ أن المتغير phrase
موجود. ولكن لم تُسند فيه قيمة بعد فعرض undefined
.
ملخص
هناك فرقين جوهرين بين var
موازنةً بِـ let/const
:
-
ليس لمتغيرات
var
نطاقًا كتليًا وأصغر نطاق لها هو في الدوال. -
تُعالج التصريحات باستعمال
var
عند بدء الدالة (أو بدء السكربت، للمتغيرات العمومية).
هناك فرق آخر صغير يتعلّق بالكائن العمومي وسنشرحه في الفصل التالي.
بهذا، غالبًا ما يكون استعمال var
أسوأ بكثير من let
بعدما عرفت الفروق بينها، فالمتغيرات على مستوى الكُتل أمر رائع جدًا ولهذا السبب تمامًا أُضيفت let
إلى معيار اللغة منذ زمن وصارت الآن الطريقة الأساسية (هي وconst
) للتصريح عن متغير.
ترجمة -وبتصرف- للفصل The old "var"
من كتاب The JavaScript language
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.