کاربردهای var ،let و const در جاوا اسکریپت — به زبان ساده

۱۲۲۷ بازدید
آخرین به‌روزرسانی: ۸ شهریور ۱۴۰۲
زمان مطالعه: ۸ دقیقه
دانلود PDF مقاله
کاربردهای var ،let و const در جاوا اسکریپت — به زبان سادهکاربردهای var ،let و const در جاوا اسکریپت — به زبان ساده

در این نوشته به بررسی دو روش جدید برای ایجاد متغیرها در جاوا اسکریپت (ES6) می‌پردازیم که let و const هستند. در این مسیر تفاوت‌های بین var ،let و const و همچنین موضوعاتی مانند حیطه تعریف تابع و بلوک، hoisting متغیرها و تغییرناپذیری (immutability) را بررسی می‌کنیم.

997696

ES2015 (یا ES6) دو روش جدید برای ایجاد متغیرها معرفی کرده است که شامل var و const می‌شود. اما پیش از آن که عملاً تفاوت‌های بین این موارد را بررسی کنیم، برخی موارد وجود دارند که با آن‌ها آشنا شویم. این موارد شامل اعلان متغیر، مقداردهی اولیه متغیر، حیطه یا دامنه متغیر (به طور خاص حیطه تابع) و hoisting هستند.

اعلان یا مقداردهی اولیه متغیر

اعلان متغیر یک شناسه جدید را معرفی می‌کند:

1var declaration

در دستور فوق ما یک شناسه به نام declaration ایجاد کردیم. در جاوا اسکریپت متغیرها در زمان ایجاد شدن، به صورت تعریف نشده (undefined) مقداردهی اولیه می‌شوند. معنی این حرف آن است که اگر تلاش کنید متغیر declaration را چاپ کنیم، با مقدار undefined مواجه خواهیم شد.

1var declaration
2console.log(declaration)

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

1var declaration
2console.log(declaration) // undefined
3declaration = 'This is an initialization'

بنابراین در کد فوق با انتساب یک رشته به متغیر declaration آن را «مقداردهی اولیه» (initialize) می‌کنیم.

حیطه متغیر

منظور از حیطه یا دامنه متغیر و یا تابع، مکان‌هایی است که متغیر درون برنامه از آنجا قابل دسترسی است. در جاوا اسکریپت دو نوع حیطه وجود دارند، حیطه سراسری (global scope) و حیطه تابع (function scope). بر اساس تعریف رسمی:

اگر عبارت متغیر درون اعلان یک تابع باشد، متغیر با حیطه همان تابع تعریف می‌شود.

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

1function getDate () {
2  var date = new Date()
3
4  return date
5}
6
7getDate()
8console.log(date) // ❌ Reference Error

در کد فوق تلاش کرده‌ایم که به یک متغیر از خارج از تابعی که در آن اعلان شده دسترسی بیابیم. از آنجا که date دارای حیطه‌ای درون تابع getDate است، تنها از درون آن یا تابع‌های داخل آن قابل دسترسی است.

1function getDate () {
2  var date = new Date()
3
4  function formatDate () {
5    return date.toDateString().slice(4) // ✅ 
6  }
7
8  return formatDate()
9}
10
11getDate()
12console.log(date) // ❌ Reference Error

در ادامه مثال پیشرفته‌تری را بررسی می‌کنیم. فرض کنید آرایه‌ای از قیمت‌ها (prices) داریم و می‌خواهیم تابعی تعریف کنیم که با بررسی مقادیر این آرایه و همچنین مقادیر تخفیف (discount)، مبالغ دارای تخفیف را به ما بازگشت دهد. هدف نهایی چیزی مانند زیر خواهد بود:

1discountPrices([100, 200, 300],.5)

و پیاده‌سازی آن می‌تواند چیزی مانند زیر باشد:

1function discountPrices (prices, discount) {
2  var discounted = []
3
4  for (var i = 0; i < prices.length; i++) {
5    var discountedPrice = prices[i] * (1 - discount)
6    var finalPrice = Math.round(discountedPrice * 100) / 100
7    discounted.push(finalPrice)
8  }
9
10  return discounted
11}

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

1function discountPrices (prices, discount) {
2  var discounted = []
3
4  for (var i = 0; i < prices.length; i++) {
5    var discountedPrice = prices[i] * (1 - discount)
6    var finalPrice = Math.round(discountedPrice * 100) / 100
7    discounted.push(finalPrice)
8  }
9
10  console.log(i) // 3
11  console.log(discountedPrice) // 150
12  console.log(finalPrice) // 150
13
14  return discounted
15}

اگر جاوا اسکریپت تنها زبانی باشد که با آن آشنا هستید ممکن است از چنین وضعیتی تعجب کرده باشید، اما اگر با زبان‌های دیگر به خصوص آن‌هایی که دارای حیطه تعریف بلوکی هستند نیز آشنا باشید، احتمالاً بهتر متوجه این وضعیت می‌شوید.

گرچه منطقاً دلیلی وجود ندارد که بخواهیم خارج از حلقه for به متغیرهای i ،discountedPrice و finalPrice دسترسی داشته باشیم، چون علاوه بر این که این کار هیچ فایده‌ای برای ما ندارد، شاید در مواردی موجب بروز مشکل نیز بشود؛ اما از آنجا که متغیرها با var اعلان شده‌اند، دارای حیطه تابعی هستند و چنین امکانی عملاً وجود دارد.

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

Hoisting

اگر به خاطر داشته باشید، در ابتدای مقاله بیان کردیم که «در جاوا اسکریپت، متغیرها در زمان ایجاد شدن، با مقدار تعریف نشده (undefined) مقداردهی اولیه می‌شوند» این همان معنی hoisting است. مفسر جاوا اسکریپت در زمان اعلان متغیر یک مقدار پیش‌فرض undefined، را در مرحله‌ای که فاز «Creation» نامیده می‌شود به آن انتساب می‌دهد.

در ادامه مثالی ارائه شده که طرز کار hoisting را در عمل نشان می‌دهد.

1function discountPrices (prices, discount) {
2  var discounted = undefined
3  var i = undefined
4  var discountedPrice = undefined
5  var finalPrice = undefined
6
7  discounted = []
8  for (var i = 0; i < prices.length; i++) {
9    discountedPrice = prices[i] * (1 - discount)
10    finalPrice = Math.round(discountedPrice * 100) / 100
11    discounted.push(finalPrice)
12  }
13
14  console.log(i) // 3
15  console.log(discountedPrice) // 150
16  console.log(finalPrice) // 150
17
18  return discounted
19}

دقت کنید که همه اعلان‌های متغیر دارای مقدار انتسابی پیش‌فرض undefined هستند. به همین دلیل است که اگر بخواهید پیش از اعلان واقعی متغیر به آن دسترسی یابید با مقدار undefined مواجه می‌شوید.

1function discountPrices (prices, discount) {
2  console.log(discounted) // undefined
3
4  var discounted = []
5
6  for (var i = 0; i < prices.length; i++) {
7    var discountedPrice = prices[i] * (1 - discount)
8    var finalPrice = Math.round(discountedPrice * 100) / 100
9    discounted.push(finalPrice)
10  }
11
12  console.log(i) // 3
13  console.log(discountedPrice) // 150
14  console.log(finalPrice) // 150
15
16  return discounted
17}

اینک که همه چیز را در مورد var می‌دانید، نهایتاً به بررسی ایده اصلی این مقاله یعنی بررسی تفاوت‌های var، let و const می‌پردازیم.

تفاوت‌های var ،let و const

در ابتدا به مقایسه کلیدواژه‌های var و let می‌پردازیم. تفاوت اصلی بین var و let این است که var دارای حیطه تعریف تابعی است؛ اما let حیطه تعریف بلوکی دارد. معنی این حرف آن است که وقتی متغیری با کلیدواژه let ایجاد شده باشد، درون بلوکی که در آن تعریف شده و بلوک‌های تو در توی آن قابل دسترسی خواهد بود. زمانی که از بلوک صحبت می‌کنیم، منظور ما هر چیزی است که در جاوا اسکریپت درون آکولادها ({}) تعریف می‌شود و این بلوک‌ها می‌توانند شامل حلقه for یا عبارت if باشند.

بنابراین دوباره نگاهی به تابع discountPrices که پیش معرفی کردیم خواهیم داشت.

1function discountPrices (prices, discount) {
2  var discounted = []
3
4  for (var i = 0; i < prices.length; i++) {
5    var discountedPrice = prices[i] * (1 - discount)
6    var finalPrice = Math.round(discountedPrice * 100) / 100
7    discounted.push(finalPrice)
8  }
9
10  console.log(i) // 3
11  console.log(discountedPrice) // 150
12  console.log(finalPrice) // 150
13
14  return discounted
15}

به خاطر دارید که در آن تابع می‌توانستیم به متغیرهای i ،discountedPrice و finalPrice در خارج از حلقه for نیز دسترسی داشته باشیم. دلیل این مسئله آن بود که این متغیرها با کلیدواژه var تعریف شده بودند که دارای حیطه تابعی است. اما اینک متغیرها را به جای var با let اعلان می‌کنیم و سعی می‌کنیم آن را اجرا کنیم.

1function discountPrices (prices, discount) {
2  let discounted = []
3
4  for (let i = 0; i < prices.length; i++) {
5    let discountedPrice = prices[i] * (1 - discount)
6    let finalPrice = Math.round(discountedPrice * 100) / 100
7    discounted.push(finalPrice)
8  }
9
10  console.log(i) // 3
11  console.log(discountedPrice) // 150
12  console.log(finalPrice) // 150
13
14  return discounted
15}
16
17discountPrices([100, 200, 300], .5) // ❌ ReferenceError: i is not defined

همان طور که مشاهده می‌کنید ما با خطای ReferenceError: i is not defined مواجه شدیم. این خطا اعلام می‌کند که متغیر اعلان شده با کلیدواژه let دارای حیطه تابعی نیست. بنابراین تلاش برای دسترسی به i در خارج از بلوکی که در آن اعلان شده است، موجب بروز خطای رفرنس می‌شود.

1var VS let
2var: function scoped
3let: block scoped

تفاوت بعدی به مسئله Hoisting مربوط می‌شود. پیش‌تر گفتیم که منظور از Hoisting این است که مفسر جاوا اسکریپت در زمان ایجاد متغیرها به طور پیش‌فرض به آن‌ها یک مقدار تعریف نشده می‌دهد. حتی دیدیم که در عمل با log گرفتن از متغیری که اعلان شده است با مقدار undefined مواجه می‌شویم.

1function discountPrices (prices, discount) {
2  console.log(discounted) // undefined
3
4  var discounted = []
5
6  for (var i = 0; i < prices.length; i++) {
7    var discountedPrice = prices[i] * (1 - discount)
8    var finalPrice = Math.round(discountedPrice * 100) / 100
9    discounted.push(finalPrice)
10  }
11
12  console.log(i) // 3
13  console.log(discountedPrice) // 150
14  console.log(finalPrice) // 150
15
16  return discounted
17}

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

در عمل این همان وضعیتی است که با let به دست می‌آوریم. اگر شما تلاش کنید به متغیری که با کلیدواژه let اعلان شده، قبل از محلی که اعلان شده است، دسترسی پیدا کنید، به جای دریافت مقدار undefined مانند آنچه در مورد var دیدیم، با یک خطای ارجاع (ReferenceError) مواجه می‌شوید.

1function discountPrices (prices, discount) {
2  console.log(discounted) // ❌ ReferenceError
3
4  let discounted = []
5
6  for (let i = 0; i < prices.length; i++) {
7    let discountedPrice = prices[i] * (1 - discount)
8    let finalPrice = Math.round(discountedPrice * 100) / 100
9    discounted.push(finalPrice)
10  }
11
12  console.log(i) // 3
13  console.log(discountedPrice) // 150
14  console.log(finalPrice) // 150
15
16  return discounted
17}
بر اساس رای ۱۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freecodecamp
۴ دیدگاه برای «کاربردهای var ،let و const در جاوا اسکریپت — به زبان ساده»

$(‘.project-percent’).each(function(){
var $this = $(this);
var percent = $this.attr(‘percent’);
$this.css(“width”,percent+’%’);
$({animatedValue: 0}).animate({animatedValue: percent},{
duration: 2000,
step: function(){
$this.attr(‘percent’, Math.floor(this.animatedValue) + ‘%’);
},
complete: function(){
$this.attr(‘percent’, Math.floor(this.animatedValue) + ‘%’);
}
});
});
سلام این برنامه به زبان جاوااسکریپت چه تغییراتی خواهد داشت ؟

با سلام
شما گفتید: «دقت کنید که تغییر دادن یک خصوصیت شیء به معنی انتساب مقدار به آن نیست. بدین ترتیب این که یک شیء با const اعلان شده باشد، به این معنی نیست که نمی‌توان مشخصات آن را تغییر داد. بلکه صرفاً به این معنی است که نمی‌توان به آن مقدار دیگری انتساب داد.»

یعنی نمیتوان به یک آرایه یا شی عضوی اضافه کرد که این درست نیست و مثلا با متد push میتوان عضو جدیدی به آرایه اضافه کرد. در تعریف object هم میتوان عضو دیگری اضافه کرد. البته جمله مقدار دیگری به آن انتساب داد هم معلوم نیست منظور شما چیست اما در مثال شما یک شی خالی را با همان نام دوباره تعریف میکنید که معلوم است که خطا میگیرد و اصلا با متن شما همخوانی ندارد ممنون

سلام و وقت بخیر علیرضای عزیز؛
به نظر می‌رسد در تفسیر جمله‌ای که از متن نقل قول کرده‌اید، کمی شتاب داشته‌اید. چنان که در متن اشاره شده مواردی که با کلیدواژه const اعلان می‌شوند، دیگر امکان rebinding یا «انتساب» (assign) مقدار دیگر ندارند و در این صورت با خطای TypeError مواجه می‌شوند. اما با این حال امکان تغییر دادن مشخصه‌ها (Properties) در مورد آنها وجود دارد. در مورد مثالی که فرمودید، چنین چیزی در متن مشاهده نشد.
متشکر از توجه شما.

عالی بود توضیحات کافی و قابل فهم بود
خدا قوت

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *