کلیدواژه های let و const در javaScript

این کلیدواژه ها به ما کمک میکنن به بهترین روش ممکن متغیر هامون رو اعلان کنیم.
این کلیدواژه ها به ما کمک میکنن به بهترین روش ممکن متغیر هامون رو اعلان کنیم.

مقدمه

زبان javaScript در سال های اخیر تغییرات خوبی داشته. این تغییرات به صورت کلی در راستای منظم تر شدن و دقیق تر شدن jS بودن. از اصلی ترین ویژگی هایی که از سال ۲۰۱۵ به بعد و با ورژن ES6 معرفی شد دو تا کلیدواژه جدید به نام های let و const بوده. این دو کلیدواژه اعلان متغیر ها رو دقیق تر میکنن. شاید بپرسی که خوب مگه قبلا نمی شد متغیر اعلان کرد؟! چرا میشد ولی یک کم می لنگید. در ادامه مقاله توضیح میدم. (اگه حوصله خوندن نداری می تونی در آخر مقاله در قسمت «خلاصه» دستورات رو حفظ کنی و خودت رو راحت کنی!)

اعلان متغیر (Declaration) و مقداردهی (Assignment)

به این که یک متغیری رو تعریف کنی میگن Declaration. این کلمه تو زبان انگلیسی یعنی «اعلان کردن». دادن مقدار به این متغیر هم میشه مقداردهی یا همون assignment انگلیسی ها. تو jS برای اعلان کردن یک متغیر عادت کرده بودیم که از کلید واژه var استفاده کنیم. این طوری:

var x;    // Declaration اعلان
x = 12;    // Assignment مقداردهی

یا این که اصلا می شد از هیچ کلیدواژه ای استفاده نکرد. این طوری:

x = 12;    // Declaration and assignment

استفاده از var یا استفاده نکردن از کلیدواژه در ورژن های جدید jS توصیه نمیشه. چرا؟! برای درک این قضیه باید با مفهوم scope آشنا بشیم.

اسکوپ (scope)

منظور از scope محدوده ای هست که یک متغیر در اون محدوده معنی میده. مثلا کد زیر رو در نظر بگیر:

y = 12;
function print() {
    var x = 12;
    console.log(x);
    console.log(y);
}

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

به صورت کلی دو تا اسکوپ داریم:

  • محدود (local): این اسکوپ یعنی محدود به بخش خاصی از کد. مثلا تو همین مثال بالا اسکوپ متغیر x لوکال بود. محدود به تابع print.
  • سراسری (global): این اسکوپ یعنی همه جایی. برای مثال در کد بالا متغیر y اسکوپ سراسری داره. چه داخل تابع چه خارج تابع بهش دسترسی داریم.

حالا بر گردیم سر اصل داستان. در jS وقتی که یک متغیر رو با var داخل تابع اعلان می کنیم اسکوپ محدود به خودش می گیره. وقتی هم یک متغیری رو بدون کلیدواژه اعلان می کنیم اسکوپ سراسری به خودش می گیره. خوب ایراد چیه پس؟!

ایراد در این جاست که این محلی بودن اسکوپ محدود به تابع میشه نه محدود به block. بلاک؟! بلاک دیگه یعنی چی؟! به طور کلی به قسمت های کد میگن بلاک. تو jS این بلاک ها رو با استفاده از { } مشخص میکنیم. مثلا هر تابع خودش یک block حساب میشه. چون موقع تعریف کد اش رو داخل { } قرار دادیم. یک مثال دیگه:

var x = 12;
if (x > 10) {
    window.alert('Hello');
}

در کد بالا هر چیزی که داخل { } های جلوی if قرار دادیم هم یک بلاک محسوب میشه. این داستان برای for و while هم صحت داره. حالا با کلیدواژه var و یا بدون کلیدواژه اعلان کردن یک متغیر چطوری باید متغیری تعریف کنیم که محدود به بلاک باشه؟! اگه با var تعریف کنیم در کل تابع بهش دسترسی داریم (و هر بلاکی که توی اون تابع هست) و اگه بدون کلیدواژه تعریف کنیم در همه جای کد حتی خارج تابع! تکلیف چیه؟!

کلیدواژه let

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

x = 12;
for (let x = 0; x < 100; x++) {
    console.log(x)
}

در کد بالا متغیر x ای که خارج از حلقه for عه یک متغیره و متغیری که داخل for و با استفاده از let تعریف شده یک متغیر دیگست. به عبارتی اون متغیری که با let تعریف شده فقط و فقط داخل بلاک ‌for معنی میده. چنین چیزی با var ممکن نبود. به عبارت دقیق تر:

کلیدواژه let متغیر های block-scoped اعلان میکنه.

چون در اکثر مواقع ما با بلاک کد رو به رو هستیم (و خود تابع هم اصلا یک بلاکه) استاندارد تره که var رو به فراموشی بسپاریم و با let کار کنیم. هم چنین توصیه میشه که از اعلان متغیر بدون کلیدواژه خودداری بشه. ولی این همه ماجرا نیست.

Redeclaration

با declare کردن یک متغیر آشنا شدیم. یکی دیگه از تفاوت های let با var و بدون کلیدواژه اعلان کردن در اینه که تو حالت قدیمی اگه با var یک متغیری رو اعلان کنیم می تونیم دوباره هم اعلانش کنیم. این جالب نیست چون احتمال خطا رو می بره بالا. بعدشم اگه چند نفر روی یک کد کار کنن هر کسی می تونه متغیر های نفر قبلی رو دوباره برای خودش اعلان کنه. به عبارت دقیق تر:

با var و یا بدون کلیدواژه اعلان کردن، امکان redeclaration هست. ولی با let امکان redeclaration نیست.

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

کلیدواژه const

حالا بیایم از اینی هم که هست دقیق تر بشیم. وقتی با let کار کنیم میشه یک متغیری رو صرفا اعلان کرد ولی مقدار بهش نداد و بعدا مقدارش رو مشخص کرد. ولی فرض کن میخایم یک متغیری رو اعلان کنیم که مجبورمون کنه دقیقا همون موقع اعلان (declare) کردن مقدارش رو هم مشخص کنیم (assignment).. در قدیم چنین چیزی ممکن نبود ولی با کلیدواژه const این امکان فراهم شده. const هم مثل let اسکوپش به بلاک محدوده.

let x;
x = 12;

const y;    // ERROR: const variables must be assigned

const z = 12;
z = 13;    // ERROR: const variables cannot be reassigned

در کد بالا به چند نکته مهم دقت کن:

  • در بخش دوم کد نمی تونستیم بگم const x چون که وقتی با let کار میکنیم امکان redeclare کردن یک متغیر نیست. (در بخش اول یک بار x رو اعلان کردیم)
  • نمی تونیم متغیری که با کلیدواژه const اعلان میشه رو بدون مقدار رها کنیم. ارور میده. باید همون جا مقدارش رو هم مشخص کنیم.
  • با کلیدواژه const هم امکان redeclare کردن نیست برای همین بخش سوم کد از z استفاده کردیم.
  • کلیدواژه const که سخت گیر تره حتی امکان عوض کردن مقدار متغیر رو هم به ما نمیده. یعنی نمی تونیم کل مقدار رو برداریم و یک مقدار دیگه به جاش بذاریم. به عبارت دقیق تر:
کلیدواژه const امکان reassignment به ما نمیده.

برای مقادیر ساده (مثل رشته، عدد، بولین ...) این عملا یعنی این که کلیدواژه const یک متغیر تغییر ناپذیر اعلان کرده (که اصلا متغیر نیست! ثابته). ولی در مورد مقادیر پیشرفته مثل Array و Object این داستان فرق داره. وقتی که یک مقدار پیشرفته (مثل آرایه، آبجکت، تابع ...) رو با کلیدواژه const اعلان می کنیم (و دقیقا توصیه هم بر اینه که با const اعلان بشن این ها)، هر چند نمیشه کل اون مقدار پیشرفته رو برداشت و یک مقدار جدید قرار داد (نمیشه reassign کرد) ولی می تونیم اون مقدار پیشرفته رو دستکاری (manipulate) کنیم. مثلا این طوری:

const user = {
    age: 24,
    name: 'bizhan',
    os: 'linux'
};
user = 'bizhan'    // ERROR: you cannot reassign a const variable
user.age = 26;     // WORKS: you just manipulated (it is not reassignment)

Global Abatement

این همه تفاوتی که بین let و const و var و بدون کلیدواژه اعلان کردن گفتم همه داستان نیست. let و const مزایای دیگری هم دارن. بسته به این که jS رو در browser یا node (یک محیط برای اجرا jS عه که با مرورگر فرق داره و خیلی هم باحاله. عملا jS رو تبدیل به یک زبان برنامه نویسی همه فن حریف کرده) اجرا کنیم در هر صورت با یک شئ گلوبال سر و کار داریم. مثلا توی مرورگر این شئ گلوبال اسمش window عه که از همه جا بهش دسترسی داریم و یک جورایی مالک همه چیزه. (شئ گلوبال == Global object)

وقتی که یک متغیر رو بدون کلیدواژه اعلان کنیم علاوه بر این که اسکوپش Global میشه، به global object مون هم attach میشه و به صورت یکی از property های اون global object در میاد (ولی با let و const این حالت پیش نمیاد). این استاندارد نیست. ممکنه پیش فرض های شئ گلوبال مون رو عوض کنه یا با کتاب خونه هایی مثل React تداخل داشته باشه.

x = 12;
alert(x)    // 12
alert(window.x)    // 12

let y = 12;
alert(y);    // 12
alert(window.y)    // undefined

اونایی که سعی میکنن استاندارد کد بنویسن از یک مفهومی پیروی میکنن به نام Global Abatement که یعنی:

تا حد ممکن از دستکاری Global object خودداری کنیم.

خوب اومدیم و به متغیر global نیاز داشتیم. با let و const که نمیشه متغیر global اعلان کرد. از طرفی استاندارد هم میگه که شئ گلوبال رو دستکاری نکن. تکلیف چیه؟ اومدن و یک چیزی درست کردن به نام State که اون هم مثل window یک global object عه با این تفاوت که مال خودمونه و هر چه قدر دوسته داشته باشیم می تونیم دستکاریش کنیم. اصلا برای همین کار درست شده! به کار کردن با state میگن state management. مثلا توی چهارچوب Vue برای state management باید از Vuex استفاده کنی.

خلاصه

تفاوت های دیگری هم هست بین var و let و cont بدون کلیدواژه اعلان کردن. یکی از این تفاوت ها Hoist شدنه که در حوصله بحث نمی گنجه ولی می تونی تو این لینک مطالعه کنی. این مثنوی طولانی رو گفتیم! حالا گذشته از همه اینا بذار خلاصه کل این مقاله رو به صورت چند تا دستور مشخص و صریح برات لیست کنم:

  • در اعلان متغیر ها از کلیدواژه var استفاده نکن. فراموشش کن.
  • متغیر ها رو بدون کلیدواژه اعلان نکن. این روش رو فراموش کن.
  • برای مقادیر متغیر ابتدایی (مثل رشته، عدد، بولین ...) از کلیدواژه let استفاده کن.
  • برای مقادیر ثابت ابتدایی (مثلا عدد PI که همیشه همون ۳.۱۴ هست) از کلیدواژه const استفاده کن.
  • برای مقادیر پیچیده (مثلا Array, Object, Function ....) از کلیدواژه const استفاده کن.

نتیجه گیری

در عکس بالا (که از اینترنت گیر آوردم) منظور از این که میگه همه سه تا کلیدواژه function scoped هستن واسه اینه که هر تابع هم خودش در واقع یک بلاکه. به عبارتی این طوری میخاد بگه: بلاک تابع و همه بلاک های داخلش
در عکس بالا (که از اینترنت گیر آوردم) منظور از این که میگه همه سه تا کلیدواژه function scoped هستن واسه اینه که هر تابع هم خودش در واقع یک بلاکه. به عبارتی این طوری میخاد بگه: بلاک تابع و همه بلاک های داخلش


پس از این به بعد از let و const استفاده کن. نه این که بیشتر استفاده کنی ها، نه. کلا از این ۲ تا استفاده کن. راستشو بخای برای من درکش سخته که چرا jS این همه اعلان متغیر رو پیچیده کرده. به خدا تو پایتان میگی x = 1 و تموم! حالا باز جای شکرش باقیه که مجبورمون نمیکنه همون دم اعلان جنس متغیر رو هم بهش بگیم (مثل ++c). امیدوارم که از این مقاله خوشت اومده باشه. در نهایت خوشحال میشم نظرت درباره مقاله رو با یک کامنت بهم بگی.