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

در ES5 زمانی که شما یک متغیر با استفاده از کلمه کلیدی var
تعریف می کردید،scope متغیر یا global یا local بود.اگر شما یک متغیر رو خارج از تابع declare کنید، scope متغیر global خواهد بود. زمانی که شما یک متغیر را درون تابع declare کنید، scope متغیر local خواهد بود.
ES6 یک روش جدید با استفاده از کلمه کلیدی let
برای تعریف متغیر فراهم کرد.کلمه کلیدی let
مشابه با var
است، با این تفاوت که متغیر ها blocked-scope هستند.برای مثال:
1 |
let variable_name; |
در جاوا اسکریپت block ها با curly braces {}
مشخص می شوند، برای مثال if else
, for
, do while
, while
, try catch
و …
1 2 3 |
if(condition) { // inside a block } |
به مثال زیر توجه کنید:
1 2 3 4 5 6 |
let x = 10; if (x == 10) { let x = 20; console.log(x); // 20: reference x inside the block } console.log(x); // 10: reference at the begining of the script |
این script چگونه کار می کند:
- در ابتدا متغیر
x
را با مقدار اولیه 10 تعریف کردیم. - سپس یک متغیر جدید با نام یکسان
x
درونif
block با مقدار اولیه 20 تعریف کردیم. - سپس خروجی متغیر
x
را درون و بعد ازif
block در کنسول چاپ کردیم.
به این دلیل که کلمه کلیدی let
متغیر ها را به صورت block-scoped نعریف می کند، متغیر x
درون if
block یک متغیر جدید است.بنابراین مقدار x
درون کنسول برابر با 20
است.
زمانی که موتور جاوا اسکریپت اجرای if
block را تمام می کند،متغیر x
خارج از if
block است.بنابراین مقدار متغیر x
بعد از if
block برابر با 10
است.
⇐ اگه علاقه مند به محتوای ویدئویی هستید، در چنل یوتوبمون هم به طور مفصل در قالب یک ویدئو در مورد let صحبت کردیم که از اینجا میتونید ویدئو رو ببینید.
let و global object در جاوا اسکریپت
زمانی که شما یک متغیر global با استفاده از کلمه کلیدی var
تعریف می کنید،شما متغیر را به لیست property های global object اضافه می کنید.در مرورگرها global object همان window
است.برای مثال:
1 2 |
var a = 10; console.log(window.a); // 10 |
با این وجود، زمانی که شما یک متغیر را با استفاده از کلمه کلیدی let
تعریف می کنید،متغیر به عنوان property به global object اضافه نمی شود.برای مثال :
1 2 |
let b = 20; console.log(window.b); // undefined |
let و callback function در حلقه for
به مثال زیر توجه کنید:
1 2 3 4 5 |
for (var i = ; i < 5; i++) { setTimeout(function () { console.log(i); }, 1000); } |
هدف کد این است که اعداد 0 تا 4 را در هر یک ثانیه در کنسول چاپ کند. با این حال ، عدد 5 را پنج بار در خروجی نمایش می دهد:
1 2 3 4 5 |
5 5 5 5 5 |
در این مثال، متغیر i
یک global variable است.بعد از حلقه، مقدار آن برابر با است.زمانی که callback functions پاس داده شده به تابع ()
setTimeout
اجرا می شود،همان متغیر i با مقدار 5 را ارجاع می دهد.
در ES5 برای حل این مشکل می توانید از یک scope دیگر استفاده کنید،بنابراین هر callback function به یک متغیر جدید ارجاع می دهد.برای ایجاد یک scope جدید، شما نیاز دارید یک تابع ایجاد کنید.شما می توانید از الگوی IIFE مشابه زیر استفاده کنید
1 2 3 4 5 6 7 |
for (var i = ; i < 5; i++) { (function (j) { setTimeout(function () { console.log(j); }, 1000); })(i); } |
خروجی:
1 2 3 4 5 |
1 2 3 4 |
در ES6، کلمه کلیدی let
در هر بار تکرار حلقه یک متغیر جدید declares می کند.بنابراین شما فقط نیاز دارید،کلمه کلیدی var
را با let
برای حل این مشکل جایگزین کنید:
1 2 3 4 5 |
for (let i = ; i < 5; i++) { setTimeout(function () { console.log(i); }, 1000); } |
برای تکمیل این کد به صورت کامل با استایل ES6 ، می توانید از arrow function مشابه زیر استفاده کنید:
1 2 |
for (let i = ; i < 5; i++) { setTimeout(() => console.log(i), 1000); } |
Redeclaration
کلمه کلیدی var
به شما این اجازه را می دهد تا یک متغیر را بدون هیچ مشکلی redeclare کنید:
1 2 3 |
var counter = ; var counter; console.log(counter); // 0 |
با این وجود،redeclaring یک متغیر با استفاده از کلمه کلیدی let
باعث ایجاد خطا می شود:
1 2 3 |
let counter = ; let counter; console.log(counter); |
Error:
1 |
Uncaught SyntaxError: Identifier 'counter' has already been declared |
متیغرهای let و hoisting
بیایید مثال زیر را بررسی کنیم:
1 2 3 4 |
{ console.log(counter); // let counter = 10; } |
اجرای این کد باعث error می شود:
1 |
Uncaught ReferenceError: Cannot access 'counter' before initialization |
در این مثال، دسترسی به متغیر counter
قبل از declaring آن باعث ایجاد ReferenceError
می شود.
Temporal death zone (TDZ)
متغیری که توسط کلمه کلیدی let تعریف می شود دارای یک temporal dead zone (TDZ) است. TDZ زمان شروع بلاک تا پردازش تعریف متغیر است.
مثال زیر نشان می دهد که temporal dead zone بر اساس زمان است ، نه بر اساس مکان.
1 2 3 4 5 6 7 8 9 10 11 |
{ // enter new scope, TDZ starts let log = function () { console.log(message); // messagedeclared later }; // This is the TDZ and accessing log // would cause a ReferenceError let message= 'Hello'; // TDZ ends log(); // called outside TDZ } |
در این مثال:
در ابتدا curly brace یک block scope جدید ایجاد می کند،بنابراین TDZ شروع می شود.
سپس تابع ()
log
به متغیر message
دسترسی دارد.با این حال هنوز تابع ()
log
اجرا نشده است.
سپس، متغیر message
تعریف و با 10 مقداردهی شده است.زمان شروع block scope تا زمان دسترسی به متغیر message
را temporal death zone می نامند.زمانی که موتور جاوا اسکریپت declaration را پردازش می کند،TDZ پایان می یابد.
سرانجام، فراخوانی تابع ()
log
که به متغیر message
دسترسی دارد،خارج TDZ انجام می شود.
توجه داشته باشید، اگر شما به متغیر تعریف شده با let
در TDZ دسترسی داشته باشید،همانطور که در مثال زیر نشان داده شده است ، یک ReferenceError دریافت خواهید کرد.
1 2 3 4 5 |
{ // TDZ starts console.log(typeof myVar); // undefined console.log(typeof message); // ReferenceError let message; // TDZ ends } |
توجه کنید که متغیر myVar
اصلا وجود ندارد،بنابراین type آن برابر با undefined است.
temporal death zone prevents از ارجاع شما به یک متغیر قبل از declaration جلوگیری می کند.
خلاصه
- متغیرهایی که با استفاده از کلمه کلیدی let تعریف می شوند که block-scope هستند. ، و به global object اضافه نمی شوند.
- Redeclaring یک متغیر با استفاده از کلمه کلیدی
let
باعث ایجاد error می شود.
دیدگاهتان را بنویسید