اگر جایی کد جاوااسکریپت دیده باشید که با var نوشته شده، احتمالاً یک باگ هم کنارش دیدهاید. جواب کوتاه: با const شروع کنید، وقتی مقدار عوض میشود به let بروید، و اصلاً سراغ var نروید. دلیلش سلیقه نیست؛ var رفتارهایی دارد که ساعتها وقت دیباگ میگیرند.
var خطا نمیدهد، فقط undefined برمیگرداند
jsconsole.log(typeof x); // undefined — نه ReferenceError
var x = 5;
var قبل از اجرا به بالای اسکوپ منتقل میشود (hoisting)، ولی مقداردهیاش سرجایش میماند. یعنی خواندن متغیر قبل از تعریف، خطا نمیدهد — فقط undefined میدهد، و همین سکوت است که باگ را قایم میکند.
let و const بهجای سکوت، خطا میدهند
jsconsole.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;
این ناحیه را Temporal Dead Zone یا TDZ میگویند: از شروع اسکوپ تا خط تعریف، متغیر وجود دارد ولی لمسکردنش خطا میدهد. به نظر سختگیرانه میآید، ولی دقیقاً همان چیزی است که میخواهید — یک خطای واضح بهجای یک undefined که بعداً سر از یک محاسبهی عجیب درمیآورد.
var از {} عبور میکند، let و const نه
jsif (true) { var a = 1; }
console.log(a); // 1 — بیرون از if هم در دسترس است
if (true) { let b = 1; }
console.log(b); // ReferenceError: b is not defined
var فقط به تابع اسکوپ میشود، نه به بلوک. یعنی یک var تعریفشده داخل if یا for، بیرون از آن هم زنده است — و میتواند نام یک متغیر دیگر را در بقیهی تابع خراب کند.
باگ کلاسیک: حلقهای که همیشه عدد آخر را برمیگرداند
jsconst fns = [];
for (var i = 0; i < 3; i++) { fns.push(() => i); }
console.log(fns.map(f => f())); // [3, 3, 3]
const fns2 = [];
for (let j = 0; j < 3; j++) { fns2.push(() => j); }
console.log(fns2.map(f => f())); // [0, 1, 2]
چون var i یکی است و بین همهی تکرارها مشترک، هر تابع همان یک متغیر را میبیند — و وقتی حلقه تمام میشود، مقدارش ۳ است. let برای هر تکرار یک بایندینگ تازه میسازد، پس هر closure عدد خودش را نگه میدارد. این دقیقاً همان باگی است که قبل از ES2015 مردم را مجبور میکرد یک IIFE اضافه دور بدنهی حلقه بپیچند.
const یعنی متغیر ثابت است، نه مقدار
jsconst obj = { n: 1 };
obj.n = 2; // مجاز — خودِ obj عوض نشده، محتوایش عوض شده
console.log(obj.n); // 2
obj = {}; // TypeError: Assignment to constant variable.
const فقط جلوی reassignment را میگیرد. اگر مقدار یک آبجکت یا آرایه است، محتوایش کاملاً قابل تغییر میماند — برای فریز واقعی باید سراغ Object.freeze بروید.
کِی از کدام
| نیاز | انتخاب |
|---|---|
| مقدار دیگر عوض نمیشود | const |
| مقدار قرار است عوض شود | let |
| کد قدیمی که نباید دست بزنید | var (برای کد جدید، نه) |
اگر پروژهتان ESLint دارد، قانون no-var را روشن کنید — بهجای اینکه در ریویو کد هر بار همین را بگویید، خطا را خودِ ادیتور نشان میدهد. اگر با جاوااسکریپت از صفر شروع میکنید، دورهی جاوااسکریپت همین رفتارهای اسکوپ و closure را با تمرین واقعی جا میاندازد.





نظرها
اولین نفری باشید که نظر میدهدسؤالتان را بپرسید یا تجربهتان را بنویسید — نویسندهی مطلب پاسخ میدهد.