بررسی (let - var - const) در جاوااسکریپت

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

کلی ویژگی جالب و جدید توسط ES6 به جاوااسکریپت اضافه شده و این زبان رو محبوب تر از همیشه کرده. در کنار var که تنها روش موجود در جاوااسکریپت بود، ES6 دوتا روش جدید برای ساخت متغیرها معرفی کرده که let و const هستن. اگه تا الان از var استفاده می‌کردین و کاربرد let و const رو نمیدونین، شاید از خودتون بپرسین من که تا الان از var استفاده می‌کردم و هیچ مشکلی وجود نداشت، پس چرا باید از let استفاده کنم؟ بهتره که این مقاله رو خوب بخونین؛ چون پیشنهاد میشه کم کم با var خداحافظی کنین.


قبل از شروع بهتره با چند تا تعریف آشنا بشیم.

۱. اسکوپ (Scope) یا حوزه

اسکوپ (Scope) یا حوزه، به جاهایی گفته میشه که متغیرها قابل دسترسی و استفاده هستن

یعنی یک متغیر توی چه جاهایی قابل دسترسی هست. مثلا توی تابع یا کلاس.

متغیرهای سراسری دارای حوزه Global هستن (Global Scope). یعنی همه جا در دسترس هستن.

https://virgool.io/Solidity/what-is-scope-in-javascript-efseqijfobdh


۲. هویستینگ (Hoisting)

این واژه توی زبان پارسی یعنی بالا بردن یه چیزی.

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

با Hoisting توی هر آیتم var و let و const بیشتر آشنا می‌شیم. حالا هر ۳ مورد رو می‌تونیم بهتر بررسی کنیم.

https://virgool.io/Solidity/what-is-hoisting-in-javascript-eljqu39tvcp9


تعریف متغیر با var

قبل از اینکه ES6 معرفی بشه، تنها راه موجود ساخت متغیرها تو جاوااسکریپت var بود. استفاده از var باعث به وجود اومدن مشکلاتی می‌شد و به همین دلیل به وجود اومدن یک راه جدید رو الزامی کرد. قبل از اینکه درباره این مشکلات صحبت کنیم، بیاین درباره var بیشتر بدونیم.

متغیرهایی که با var تعریف میشن، می‌تونن یا حوزه سراسری داشته باشن یا لوکال (محلی). یک متغیر وقت بیرون از یک تابع تعریف شده باشه حوزه سراسری داره. یعنی وقتی یک متغیر با var بیرون از یک تابع تعریف شده باشه، توی همه جای برنامه در دسترس هست. حتی درون تابع:

var x = &quotThis is a book&quot

function cookie() {
  alert(x);
}

cookie(x); // This is a book

توی مثال بالا، ما متغیر x رو درون تابع هم داریم.

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

function yoo() {
  var x = 1;
}

yoo();
alert(x); // error: x is not defined


تعریف دوباره متغیر در var

وقتی متغیری مثلاً x، با var تعریف میشه، این قابلیت وجود داره که یک متغیر دیگه با var، با همون نام، یعنی x، تعریف بشه:

var color = &quotYellow&quot
var color = &quotNavy&quot // ok


هویستینگ Hoisting در var

به کد زیر و به اینکه متغیر y کجا تعریف شده دقت کنید:

alert(y); // undefined
var y = &quotStreet&quot

در واقع کد بالا توی جاوااسکریپت بصورت زیر تفسیر میشه:

var y;
alert(y); // undefined
y = &quotStreet&quot

همونطور که می‌بینیم، برای y یک Hoisting صورت گرفت. یعنی خط ۲ توی کد اول، باعث شد که y بره به اول حوزه خودش و با مقدار undefined تعریف بشه.


مشکل var

به مثال زیر دقت کنین:

var greeter = &quotHey Hi&quot
var times = 4;

if (times > 3) {
  var greeter = &quotHello&quot 
}

alert(greeter) //&quotHello&quot

وقتی توی خط سوم شرط ما برقرار میشه، متغیر greeter دوباره تعریف و مقدارش عوض میشه. خب اگه بطور عمد این کار رو انجام داده باشیم، ظاهرا مشکلی نداره. اما وقتی متغیر greeter از قبل توی کد ما تعریف شده باشه ولی ما از وجودش بی خبر باشیم، احتمال اینکه کد ما دچار باگ بشه زیاده. اونم باگی که ظاهراً مخفیانه هست! :)

برای همین دلایل بود که let و const معرفی شدن.


تعریف متغیر با let

متغیرهایی که با let تعریف میشن، دارای اسکوپ بلاکی (Block Scoped) هستن. یعنی چی؟ بلاک به قسمتی از کد گفته میشه که بین براکت { } قرار میگیره. پس متغیرهایی که با let توی بلاک تعریف میشن، فقط توی همون بلاک قابل دسترسی هستن، که به اصطلاح میگن Block Scoped. مثال زیر رو ببینید:

let greeting = &quotSay Hi&quot
let times = 4;

if (times > 3) {
  let hello = &quotSay Hello&quot
  alert(hello); // &quotSay Hello&quot
}

alert(hello) // error: hello is not defined

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


تعریف مجدد متغیر با let

متغیرهای let می‌تونن مقدار جدیدی بگیرن، ولی نمی‌تونن دوباره تعریف بشن:

let x = 24;
x = 28; // ok

کد بالا کاملاً درسته و بدون مشکل. اما کد زیر به ما ارور میده، چون داریم یک متغیری رو که قبلا با let (یا var) تعریف شده رو دوباره با let تعریف می‌کنیم:

let x = 24;
let x = 28; // error: redeclaration of let x


// ...

var y = 45;
let y = 48; // error: redeclaration of let y

پس با توجه به اینکه متغیرهای let بلاک اسکوپ هستن، میشه داخل اسکوپ‌های مختلف متغیرهایی با همون نام رو با let تعریف کرد. بنابراین کد زیر بدون مشکل اجرا میشه:

let greeting = &quotHi&quot

if (true) {
  let greeting = &quotHello&quot
  alert(greeting); //&quotHello&quot
}

alert(greeting); //&quotHi&quot

با توجه به کد بالا، مشکلاتی رو که تو قسمت var بررسی کردیم، دیگه برای let به وجود نمیاد.


هویستینگ Hoisting در let

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

alert(f);
let f = 12;
// ReferenceError: can't access lexical declaration `f' before initialization


تعریف متغیر با const

متغیرهایی که با const (کانست) تعریف میشن، همون ویژگی‌هایی رو دارن که متغیرهای let دارن، با این تفاوت که مقدار متغیرهای const رو دیگه نمیشه تغییر داد.

متغیرهای const مثل let بلاک اسکوپ هستن؛ یعنی همونطور که توی قسمت let توضیح دادم، متغیرهای const هم فقط توی حوزه خودشون قابل دسترسی هستن.


مقداردهی و تعریف دوباره const

متغیرهای const وقتی تعریف و مقداردهی بشن، دیگه نمیتونن دوباره تعریف و همچنین مقداردهی بشن.

const p = 10;
p = 4;
// TypeError: invalid assignment to const `p'
const p = 12;
const p = 24;
// SyntaxError: redeclaration of const p

این قضیه درباره متغیرهایی که مقدار آبجکتی دارن فرق میکنه. وقتی یک متغیر const یک مقدار آبجکتی داره، آیتم‌های موجود در آبجکت رو میشه بدون هیچ مشکلی تغییر داد:

const person = {
  name: &quotJohn&quot,
  lastname: &quotDoe&quot
}

person.name = &quotDavood&quot

console.log(person); // { name: &quotDavood&quot, lastname: &quotDoe&quot }

این نکته رو در نظر داشته باشید که ما نمی‌تونیم کل آبجکت رو جایگزین کنیم. کد زیر به ما خطا برمی‌گردونه:

const person = {
  name: &quotJohn&quot,
  lastname: &quotDoe&quot
}

const person = {
  name: &quotDavid&quot,
  lastname: &quotBeckham&quot
}

// SyntaxError: redeclaration of const person

متغیرهای const همیشه باید با یک مقدار پیاده‌سازی بشن:

const u;
// SyntaxError: missing = in const declaration


هویستینگ Hoisting در const

هویستینگ Hoisting در const درست مثل let هست. یعنی متغیرها به بالای حوزه خودشون میرن ولی پیاده‌سازی نمی‌شن. پس اگه متغیری رو قبل از اینکه پیاده‌سازی کنیم صدا بزنیم، خطا می‌گیریم.



خلاصه

  • متغیرهای var یا دارای حوزه سراسری هستن، یا حوزه تابعی. متغیرهای let و const دارای حوزه بلاکی هستن (Block Scoped).
  • متغیرهای var می‌تونن دوباره با var تعریف و همچنین مقداردهی بشن. متغیرهای let دوباره نمیتونن تعریف بشن، ولی می‌تونن دوباره مقداردهی بشن. متغیرهای const، نه می‌تونن دوباره تعریف و نه دوباره مقداردهی بشن.
  • متغیرهای var و let و const موقع عملیات Hoisting، بالای حوزه خودشون میرن، به طوری که متغیرهای var با مقدار undefined پیاده‌سازی میشن. درصورتی که توی let و const، متغیرها با هیچ مقداری پیاده‌سازی نمیشن.
  • وقتی متغیرهای var و let رو تعریف می‌کنیم، می‌تونیم بهشون مقدار ندیم و بعداً این کار رو انجام بدیم. ولی متغیرهای const رو همیشه باید با مقدار، پیاده‌سازی کنیم.


خب دوستان امیدوارم از این مقاله استفاده کرده باشین. اگه سوال یا نظری دارید حتما توی قسمت نظرات از من بپرسید.

منبع:

https://sarahchima.com/blog/var-let-const-difference