اذهب إلى المحتوى

إفادة var القديمة في جافاسكربت


صفا الفليج

ذكرنا في أوائل الفصول حين تكلمنا عن المتغيرات - ذكرنا ثلاث طرائق للتصريح عنها:

  1. let
  2. const
  3. 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"‎ إجراءان اثنان:

  1. التصريح عن المتغير باستعمال var
  2. إسناد قيمة للمتغير باستعمال ‎=‎.

يتعامل المحرّك مع التصريحات متى بدء تنفيذ الدالة (إذ التصريحات تطفو)، ولكنّ عبارة الإسناد لا تعمل إلّا حيثما ظهرت، فقط. إذًا فالشيفرة تعمل بهذا النحو فعليًا:

function sayHi() {
  var phrase; // ‫بادئ ذي بدء، يعمل التصريح...

  alert(phrase); // غير معرّف

  phrase = "Hello"; // ‫...هنا.
}

sayHi();

يُعالج المحرّك التصريحات ‎var‎ حين تبدأ الدوال، وبهذا يمكننا الإشارة إليها أينما أردنا في الشيفرة. ولكن انتبه فالمتغيرات غير معرّفة حتى تُسند إليها قيم.

في الأمثلة أعلاه عمل التابِع ‎alert‎ دون أيّ أخطاء إذ أن المتغير ‎phrase‎ موجود. ولكن لم تُسند فيه قيمة بعد فعرض ‎undefined‎.

ملخص

هناك فرقين جوهرين بين ‎var‎ موازنةً بِـ ‎let/const‎:

  1. ليس لمتغيرات ‎var‎ نطاقًا كتليًا وأصغر نطاق لها هو في الدوال.
  2. تُعالج التصريحات باستعمال ‎var‎ عند بدء الدالة (أو بدء السكربت، للمتغيرات العمومية).

هناك فرق آخر صغير يتعلّق بالكائن العمومي وسنشرحه في الفصل التالي.

بهذا، غالبًا ما يكون استعمال ‎var‎ أسوأ بكثير من ‎let‎ بعدما عرفت الفروق بينها، فالمتغيرات على مستوى الكُتل أمر رائع جدًا ولهذا السبب تمامًا أُضيفت ‎let‎ إلى معيار اللغة منذ زمن وصارت الآن الطريقة الأساسية (هي و‎const‎) للتصريح عن متغير.

ترجمة -وبتصرف- للفصل The old "var" من كتاب The JavaScript language


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...