متغیرها در جاوا اسکریپت | تفاوت const و let و var

ریلیز های مختلف جاوا اسکریپت

نمودار  آپدیت های جاوا اسکریپت در طول زمان
نمودار آپدیت های جاوا اسکریپت در طول زمان


در این بلاگ قصد دارم چیزی که از متغیرها در جاوااسکریپت یادگرفتم رو به شما منتقل کنم. مطالبی که در ادامه می‌خونید حاصل تحقیق و مطالعه از منابع مختلف هست و عکس هایی که استفاده شده اند ممکنه از بلاگ ها یا ویدئوهای مختلف برداشته شده باشند.

هر سال نسخه جدیدی از جاوااسکریپت ارائه می شود که در آن تغییراتی ایجاد می شود که کار را برای برنامه نویسان راحت تر می کند.

مهمترین آپدیت اکمااسکریپت ES6 شامل تغییراتی از جمله اضافه شدن Spread، Destructuring، Template literal، let، const، Arrow functions، classes و ... می باشد.

قبل از ES6 تنها راه تعریف متغیر در جاوا اسکریپت استفاده از var بود. برای اینکه بتونیم قابلیت ها و تفاوت های متغیر های جاوااسکریپت مدرن یعنی var و let و const رو متوجه بشیم، اول باید با مقهوم اسکوپ (scope) در جاوا اسکریپت آشنا بشیم.

اسکوپ

در جاوااسکریپت هر متغیر یک name دارد که با آن شناخته می شود. در هر متغیر یک مقدار یا value وجود دارد. این متغیر می تواند در اسکوپ (محیط یا فضا) مختلفی قرار بگیرد. در تصویر زیر می تونید ببینید که محیط window در واقع بزرگترین global scope ما است که اگر یک متغیر در آن تعریف شود در تمام محیط های دیگه که زیر مجموعه window هستند، قابل دسترسی است.

مفهوم اسکوپ در جاوااسکریپت
مفهوم اسکوپ در جاوااسکریپت


در تصویر زیر نیز می توانید با یک مثال تفاوت این سه Scope را ببینید.

مثال اسکوپ در دنیای واقعی برای فهم بیشتر
مثال اسکوپ در دنیای واقعی برای فهم بیشتر

همون طور که در تصویر بالا می‌بینید، قوانین مربوط به حقوق بشر حکم گلوبال اسکوپ رو دارند و جامعیت اونا بیشتر از قوانین مربوط به یک کشور هست و همین طور قوانین یک کشور در اسکوپ بالاتری نسبت به قوانین یک ایالت از یک کشور قرار دارند.

مفهوم Hoisting در Variable و function

هویستینگ به زبون ساده یعنی اینکه بتونیم از یک متغیر یا یک تابع قبل از اینکه تعریفش کرده باشیم، استفاده کنیم.

همین اول باید بگم که مبحث hoisting اصلا در زبان های دیگه مثل پایتون، جاوا، C، C++ و ... وجود نداره و ممکنه باعث ایجاد خطا در کد ما بشه. بنابراین بهتره که کلا توابع و متغیر هامون رو اول تعریف کنیم و بعد ازشون استفاده کنیم.


فقط قسمت declaration هوستینگ میشه (به بالا میره)
فقط قسمت declaration هوستینگ میشه (به بالا میره)
هوستینگ داخل اسکوپ خود متغیر صورت میگیره
هوستینگ داخل اسکوپ خود متغیر صورت میگیره


تفاوت var، let و const

وقتی متغیر با let و const داخل تابع یا بلاک تعریف بشه، فقط داخل همون تابع یا بلاک (اسکوپ خودش) قابل دسترسه و در اسکوپ بالاتر قابل دسترسی نیست.

اما متغیری که با var تعریف بشه دو حالت داره:

  • اگر داخل تابع تعریف شده باشد مثل let و const فقط داخل اسکوپ خودش قابل دسترس است.
  • اما اگر داخل بلاک if یا for تعریف شده باشد ممکن است با یک متغیر دیگه که خارج از تابع یا بلاک است هم نام باشد. در این صورت (به دلیل قابلیت redeclare شدن var) مقدار آن متغیری که خارج از تابع یا بلاک است را به خود می گیرد. به همین دلیل داخل تابع یا بلاک برای تعیین متغیر از const و let استفاده می کنند.

متغیر var در جاوا اسکریپت


اینجا اسم هر دو متغیر name هست اما اونی که در فانکشن اسکوپ هست فقط در اسکوپ خودش در دسترسه

در اینجا var چون فقط داخل فانکشن اسکوپ تعریف شده دیگه بیرون اسکوپ خودش در دسترس نیست
در اینجا var چون فقط داخل فانکشن اسکوپ تعریف شده دیگه بیرون اسکوپ خودش در دسترس نیست

در تصویر بالا می بینید که var وقتی داخل function scope تعریف می شود، فقط داخل همین فانکشن valid است و بیرون از اون valid نیست. (دقیقا مثل let) اما فرق let و var دقیقا همینجاست! در واقع var فقط زمانی که داخل function scope باشه این ویژگی رو داره و اگر در block scope تعریف بشه داستان جور دیگری خواهد بود که در ادامه توضیح می دهم.

حالا حالت زیر رو ببینید:

متغیر ها رو میشه بدون let ,const یا var هم تعریف کرد. در این صورت این متغیر اسکوپ گلوبال می گیره و اولویتش از همه بالاتر میشه. یعنی مثلا اگه یه متغیر به اسم name داخل تابع یا بلاک با var تعریف کنیم و یک متغیر به اسم name بدون var بیرون از تابع تعریف کنیم (یا بلعکس)، اولویت فراخوانی و اجرا با متغیری است که بدون var باشه. مثال زیر رو ببینید:

پس متغیر var که گفتیم اگر داخل فانکشن اسکوپ تعریف بشه دیگه بیرون از اسکوپ خودش در دسترس نیست یک استثنا هم داره. اونم همین مثال بالاست.

متغیر let در جاوا اسکریپت

اگر متغیر را با let داخل یک بلاک تعریف کنیم و بعد بیرون از بلاک هم دقیقا با همان اسم و با let متغیر را تعریف کنیم، دیگه مثل var نیست که با هم قاطی بشن. در واقع let داخل بلاک فقط داخل همان بلاک قابل دسترسی است و به صورت زیر خواهد بود:


حالا همین قطعه کد رو با var می نویسیم تا ببینیم چه اتفاقی می افتد:


همان طور که دیدید، var که داخل block scope است با var که داخل global scope بود هر دو یک نام داشتند و به همین دلیل var داخل block scope با var قبل از خودش جایگزین شد. به این ویژگی var ها میگن redeclare شدن. در واقع var ها میتونن redeclare بشن و در این مثال هم به همین دلیل خروجی معادل value داده شده به var داخل block scope شده است.

اما let قابلیت redeclare شدن نداره. در واقع ما نمیتونیم دو تا let هم نام در یک scope مشترک داشته باشیم و هر let فقط در scope خودش قابل دسترسی هست.

حالا که در مورد redeclare شدن صحبت کردیم باید به reassign کردن هم اشاره کنیم.


در حقیقت reassign کردن یعنی اینکه متغیر رو بدون var، let یا const بنویسیم. این قابلیت برای var و let وجود داره اما برای const وجود نداره.

یه نگاه به جدول زیر بندازید:


لکسیکال اسکوپ

لکسیکال اسکوپ به این معنی است که هر تابع و بلاکی می تواند به متغیر های تعریف شده در خارج از اسکوپ خود (گلوبال اسکوپ) دسترسی داشته باشد.

اما متغیر هایی که داخل خود فانکشن یا بلاک اسکوپ تعریف می شوند فقط داخل همان اسکوپ قابل دسترسی هستند و در گلوبال اسکوپ در دسترس نیستند.