متغیرها یک ساختار داده ای هستند که یک نام نماینده را به یک مقدار اختصاص می دهند. آنها می توانند حاوی داده هایی از هر نوع باشند.
نام متغیر را شناسه می نامند. یک شناسه معتبر باید از این قوانین پیروی کند:
- شناسه ها می توانند شامل حروف یونیکد، علائم دلار ($)، نویسه های زیرخط (_)، ارقام (0-9)، و حتی برخی از کاراکترهای یونیکد باشند.
- شناسه ها نمی توانند حاوی فضای خالی باشند، زیرا تجزیه کننده از فضای خالی برای جداسازی عناصر ورودی استفاده می کند. به عنوان مثال، اگر بخواهید به جای
myVariable
یک متغیرmy Variable
را صدا بزنید، تجزیه کننده دو شناسهmy
وVariable
را می بیند و یک خطای نحوی ("token unnexpected: identifier") ایجاد می کند. شناسه ها باید با یک حرف، زیرخط (
_
) یا علامت دلار ($
) شروع شوند. برای جلوگیری از سردرگمی بین اعداد و شناسهها، نمیتوانند با اعداد شروع شوند:let 1a = true; > Uncaught SyntaxError: Invalid or unexpected token
اگر جاوا اسکریپت اعداد را در ابتدای یک شناسه مجاز میکرد، به شناسههایی که فقط از اعداد تشکیل شدهاند اجازه میدادند و باعث تضاد بین اعداد استفادهشده بهعنوان اعداد و اعداد استفادهشده بهعنوان شناسه میشد:
let 10 = 20 10 + 5 > ?
" کلمات رزرو شده " که قبلاً از نظر نحوی معنی دارند نمی توانند به عنوان شناسه استفاده شوند.
شناسه ها نمی توانند شامل کاراکترهای خاص باشند (
! . , / \ + - * =
).
موارد زیر قوانین سختگیرانه ای برای ایجاد شناسه ها نیستند، اما بهترین روش های صنعت هستند که حفظ کد شما را آسان تر می کنند. اگر پروژه خاص شما دارای استانداردهای متفاوتی است، به جای آن از استانداردها پیروی کنید.
با پیروی از مثالی که توسط روشها و ویژگیهای داخلی جاوا اسکریپت تنظیم شده است، casel case (همچنین به عنوان "camelCase" تلطیف شده است) یک قرارداد بسیار رایج برای شناسههایی است که از چندین کلمه تشکیل شده است. حالت شتر عمل بزرگ کردن حرف اول هر کلمه به جز حرف اول برای بهبود خوانایی بدون فاصله است.
let camelCasedIdentifier = true;
برخی از پروژه ها بسته به زمینه و ماهیت داده ها از قراردادهای نامگذاری دیگری استفاده می کنند. برای مثال، حرف اول یک کلاس معمولاً با حروف بزرگ نوشته میشود، بنابراین در نامهای کلاسهای چند کلمهای معمولاً از یک نوع شتر استفاده میشود که معمولاً «جعبه شتر بالایی» یا پاسکال نامیده میشود.
class MyClass {
}
شناسهها باید ماهیت دادههایی را که دارند بهطور مختصر توصیف کنند (به عنوان مثال، currentMonthDays
نام بهتری از theNumberOfDaysInTheCurrentMonth
است) و در یک نگاه به وضوح خوانده شود ( originalValue
بهتر از val
است). شناسههای myVariable
که در سراسر این ماژول استفاده میشوند، در زمینه نمونههای مجزا کار میکنند، اما در کد تولید بسیار مفید نیستند، زیرا هیچ اطلاعاتی در مورد دادههایی که دارند ارائه نمیدهند.
شناسهها نباید در مورد دادههایی که دارند خیلی مشخص باشند، زیرا مقادیر آنها بسته به نحوه عملکرد اسکریپتها روی آن دادهها یا تصمیمهایی که نگهدارندههای آینده میگیرند میتواند تغییر کند. برای مثال، متغیری که در ابتدا به miles
شناسه داده میشد، ممکن است نیاز به تغییر به مقداری بر حسب کیلومتر در پروژه داشته باشد، و از نگهدارندهها میخواهد که هر مرجعی را به آن متغیر تغییر دهند تا از سردرگمی آینده جلوگیری شود. برای جلوگیری از این امر، به جای آن distance
به عنوان شناسه خود استفاده کنید.
جاوا اسکریپت هیچ امتیاز یا معنای خاصی به شناسه هایی که با کاراکترهای زیرخط ( _
) شروع می شوند، نمی دهد، اما معمولاً برای نشان دادن اینکه یک متغیر، متد یا ویژگی "خصوصی" است، استفاده می شود، به این معنی که فقط برای استفاده در داخل در نظر گرفته شده است. زمینه شی که حاوی آن است، و نباید خارج از آن زمینه به آن دسترسی پیدا کرد یا تغییر داد. این قراردادی است که از زبان های برنامه نویسی دیگر منتقل شده است و قبل از اضافه شدن ویژگی های خصوصی جاوا اسکریپت است.
اعلام متغیر
راه های متعددی برای آگاه کردن جاوا اسکریپت از یک شناسه وجود دارد، فرآیندی به نام «اعلان» یک متغیر. یک متغیر با استفاده از کلمات کلیدی let
، const
یا var
اعلام می شود.
let myVariable;
let
یا var
برای اعلام متغیری که در هر زمان می توان آن را تغییر داد، استفاده کنید. این کلمات کلیدی به مفسر جاوا اسکریپت می گویند که رشته ای از کاراکترها یک شناسه است که ممکن است حاوی مقدار باشد.
هنگام کار در یک پایگاه کد مدرن، به جای var
از let
استفاده کنید. var
هنوز در مرورگرهای مدرن کار می کند، اما برخی از رفتارهای غیر شهودی دارد که در نسخه های اولیه جاوا اسکریپت تعریف شده بودند، و بعداً برای حفظ سازگاری با عقب نمی توان آن را تغییر داد. let
در ES6 اضافه شد تا برخی از مشکلات مربوط به طراحی var
را برطرف کند.
یک متغیر اعلام شده با اختصاص مقداری به متغیر مقداردهی اولیه می شود. از یک علامت تساوی ( =
) برای تخصیص یا تخصیص مجدد یک مقدار به یک متغیر استفاده کنید. می توانید این کار را به عنوان بخشی از همان عبارتی که آن را اعلام می کند انجام دهید:
let myVariable = 5;
myVariable + myVariable
> 10
همچنین می توانید یک متغیر را با let
(یا var
) بدون مقداردهی اولیه آن اعلام کنید. اگر این کار را انجام دهید، مقدار اولیه متغیر undefined
است تا زمانی که کد شما به آن مقداری اختصاص دهد.
let myVariable;
myVariable;
> undefined
myVariable = 5;
myVariable + myVariable
> 10
متغیر با مقدار undefined
با متغیر تعریف نشده ای که شناسه آن هنوز اعلام نشده است متفاوت است. ارجاع به متغیری که اعلان نکرده اید باعث خطا می شود.
myVariable
> Uncaught ReferenceError: myVariable is not defined
let myVariable;
myVariable
> undefined
ارتباط یک شناسه با یک مقدار به طور کلی "باید" نامیده می شود. نحوی که از کلیدواژههای let
، var
یا const
پیروی میکند، "لیست الزام آور" نامیده میشود و امکان چندین اعلان متغیر جدا شده با کاما را میدهد (که با نقطه ویرگول مورد انتظار ختم میشوند). این باعث می شود قطعه کد زیر از نظر عملکردی یکسان باشد:
let firstVariable,
secondVariable,
thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;
تخصیص مجدد مقدار متغیر از let
(یا var
) استفاده نمی کند، زیرا جاوا اسکریپت از قبل می داند که متغیر وجود دارد:
let myVariable = true;
myVariable
> true
myVariable = false;
myVariable
> false
میتوانید متغیرها را بر اساس مقادیر موجود، مقادیر جدیدی تخصیص دهید:
let myVariable = 10;
myVariable
> 10
myVariable = myVariable * myVariable;
myVariable
> 100
اگر سعی کنید یک متغیر را با استفاده از let
in یک محیط تولید مجدداً اعلام کنید، یک خطای نحوی دریافت خواهید کرد:
let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable
ابزارهای توسعه دهنده مرورگرها در مورد اعلام مجدد let
(و class
) سهل گیرتر هستند، بنابراین ممکن است همان خطا را در کنسول توسعه دهنده خود مشاهده نکنید.
برای حفظ سازگاری مرورگر قدیمی، var
امکان اعلام مجدد غیرضروری بدون خطا در هر زمینه را میدهد:
var myVariable = true;
var myVariable = false;
myVariable\
> false
const
از کلمه کلیدی const
برای اعلام یک ثابت استفاده کنید، یک نوع متغیر که باید فورا مقداردهی اولیه شود و سپس قابل تغییر نیست. شناسههای ثابتها از همه قوانین مشابه متغیرهای اعلام شده با استفاده از let
(و var
) پیروی میکنند:
const myConstant = true;
myConstant
> true
شما نمی توانید یک ثابت را بدون تخصیص فوراً یک مقدار اعلام کنید، زیرا ثابت ها را نمی توان پس از ایجاد دوباره تخصیص داد، بنابراین هر ثابت بدون مقدار اولیه برای همیشه undefined
باقی می ماند. اگر بخواهید یک ثابت را بدون مقداردهی اولیه اعلام کنید، با یک خطای نحوی مواجه می شوید:
const myConstant;
Uncaught SyntaxError: missing = in const declaration
تلاش برای تغییر مقدار یک متغیر اعلام شده با const
به روشی که ممکن است مقدار متغیر wit را با let
(یا var
) تغییر دهید، یک خطای نوع ایجاد می کند:
const myConstant = true;
myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'
با این حال، هنگامی که یک ثابت با یک شی مرتبط است، ویژگی های آن شی را می توان تغییر داد.
const constantObject = { "firstvalue" : true };
constantObject
> Object { firstvalue: true }
constantObject.secondvalue = false;
constantObject
> Object { firstvalue: true, secondvalue: false }
ثابتی که حاوی یک شی است یک مرجع تغییرناپذیر به یک مقدار داده قابل تغییر است. در حالی که خود ثابت را نمی توان تغییر داد، ویژگی های شی ارجاع شده را می توان تغییر داد، به آن اضافه کرد یا حذف کرد:
const constantObject = { "firstvalue" : true };
constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'
زمانی که انتظار ندارید متغیری دوباره تخصیص داده شود، بهترین کار این است که آن را ثابت کنید. استفاده از const
به تیم توسعه شما یا نگهبانان آینده پروژه میگوید که آن مقدار را تغییر ندهند، تا از زیر پا گذاشتن مفروضاتی که کد شما در مورد نحوه استفاده از آن میسازد اجتناب کنند - به عنوان مثال، اینکه یک متغیر در نهایت با یک نوع داده مورد انتظار ارزیابی میشود.
دامنه متغیر
محدوده یک متغیر بخشی از یک اسکریپت است که در آن متغیر در دسترس است. خارج از محدوده متغیر، تعریف نمی شود – نه به عنوان یک شناسه حاوی مقدار undefined
، بلکه به گونه ای که گویی اعلام نشده است.
بسته به کلمه کلیدی که برای تعریف یک متغیر استفاده میکنید و زمینهای که در آن آن را تعریف میکنید، میتوانید متغیرها را برای بلوک عبارات ( محدوده بلوک )، توابع جداگانه ( حوزه تابع )، یا کل برنامه جاوا اسکریپت ( گستره جهانی ) قرار دهید.
محدوده را مسدود کنید
هر متغیری که با استفاده از let
یا const
اعلام میکنید به نزدیکترین دستور بلوک حاوی آن اختصاص داده میشود، به این معنی که متغیر فقط در آن بلوک قابل دسترسی است. تلاش برای دسترسی به یک متغیر با محدوده بلوک خارج از بلوک حاوی آن، همان خطای تلاش برای دسترسی به متغیری را ایجاد می کند که وجود ندارد:
{
let scopedVariable = true;
console.log( scopedVariable );
}
> true
scopedVariable
> ReferenceError: scopedVariable is not defined
تا جایی که به جاوا اسکریپت مربوط می شود، یک متغیر با محدوده بلوکی خارج از بلوکی که آن را در بر می گیرد وجود ندارد . به عنوان مثال، می توانید یک ثابت را در داخل یک بلوک اعلام کنید، و سپس ثابت دیگری را در خارج از آن بلوک که از همان شناسه استفاده می کند، اعلام کنید:
{
const myConstant = false;
}
const myConstant = true;
scopedConstant;
> true
اگرچه یک متغیر اعلام شده نمی تواند به بلوک والد خود گسترش یابد، اما برای همه بلوک های نسل در دسترس است :
{
let scopedVariable = true;
{
console.log( scopedVariable );
}
}
> true
مقدار یک متغیر اعلام شده را می توان از داخل یک بلوک نزول تغییر داد:
{
let scopedVariable = false;
{
scopedVariable = true;
}
console.log( scopedVariable );
}
> true
یک متغیر جدید را می توان با let
یا const
در داخل یک بلوک نزول بدون خطا مقداردهی کرد، حتی اگر از همان شناسه متغیر در بلوک والد استفاده کند:
{
let scopedVariable = false;
{
let scopedVariable = true;
}
console.log( scopedVariable );
}
> false
محدوده عملکرد
متغیرهای اعلام شده با استفاده از var
به نزدیکترین تابع حاوی خود (یا بلوک اولیه سازی ایستا در یک کلاس ) محدوده می شوند.
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
پس از فراخوانی یک تابع، این وضعیت همچنان ادامه دارد. حتی اگر متغیر در حین اجرای تابع مقداردهی اولیه شود، آن متغیر هنوز خارج از محدوده تابع در دسترس نیست:
function myFunction() {
var scopedVariable = true;
return scopedVariable;
}
scopedVariable;
> ReferenceError: scopedVariable is not defined
myFunction();
> true
scopedVariable;
> ReferenceError: scopedVariable is not defined
گستره جهانی
یک متغیر سراسری در کل یک برنامه جاوا اسکریپت، در داخل هر بلوک و توابع، برای هر اسکریپت موجود در صفحه موجود است.
در حالی که این میتواند یک پیشفرض مطلوب به نظر برسد، متغیرهایی که هر بخشی از یک برنامه میتواند به آنها دسترسی داشته باشد و آنها را تغییر دهد، میتوانند سربار غیرضروری اضافه کنند، یا حتی باعث برخورد با متغیرها در جاهای دیگر برنامه با همان شناسه شوند. این مورد برای همه جاوا اسکریپت هایی که در رندر کردن یک صفحه دخیل هستند، از جمله مواردی مانند کتابخانه های شخص ثالث و تجزیه و تحلیل کاربر، اعمال می شود. بنابراین، بهترین روش برای جلوگیری از آلوده کردن دامنه جهانی در صورت امکان است.
هر متغیری که با استفاده از var
در خارج از یک تابع والد یا با استفاده از let
یا const
خارج از بلوک والد اعلام شود، جهانی است:
var functionGlobal = true; // Global
let blockGlobal = true; // Global
{
console.log( blockGlobal );
console.log( functionGlobal );
}
> true
> true
(function() {
console.log( blockGlobal );
console.log( functionGlobal );
}());
> true
> true
اختصاص دادن یک مقدار به یک متغیر بدون اعلان صریح آن (یعنی با استفاده از var
, let
یا const
برای ایجاد آن) یک متغیر را به دامنه جهانی ارتقا می دهد، حتی زمانی که در داخل یک تابع یا بلوک مقداردهی اولیه شود. متغیری که با استفاده از این الگو ایجاد میشود، گاهی اوقات «جهانی ضمنی» نامیده میشود.
function myFunction() {
globalVariable = "global";
return globalVariable
}
myFunction()\
> "global"
globalVariable\
> "global"
بالابر متغیر
متغیرها و اعلانهای توابع در بالای محدوده خود قرار میگیرند، به این معنی که مفسر جاوا اسکریپت هر متغیری را که در هر نقطه از یک اسکریپت اعلام شده پردازش میکند و به طور موثر قبل از اجرای اسکریپت، آن را به اولین خط محدوده خود منتقل میکند. این بدان معنی است که متغیری که با استفاده از var
اعلام شده است، می تواند قبل از اینکه متغیر اعلام شود بدون اینکه با خطا مواجه شود، ارجاع داده شود:
hoistedVariable
> undefined
var hoistedVariable;
از آنجا که فقط اعلان متغیر میزبانی می شود، نه مقداردهی اولیه، متغیرهایی که به صراحت با var
، let
یا const
اعلان نشده اند، بالا نمی روند:
unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined
unhoistedVariable = true;
همانطور که قبلا ذکر شد ، به یک متغیر اعلام شده اما بدون مقدار اولیه مقدار undefined
اختصاص داده می شود. این رفتار برای اعلان های متغیر hoisted نیز اعمال می شود، اما فقط برای آنهایی که با استفاده از var
اعلان شده اند.
hoistedVariable
> undefined
var hoistedVariable = 2 + 2;
hoistedVariable\
> 4
این رفتار غیر شهودی عمدتاً از تصمیمات طراحی گرفته شده در نسخه های اولیه جاوا اسکریپت باقی مانده است و بدون خطر شکستن سایت های موجود قابل تغییر نیست.
let
و const
این رفتار را با پرتاب خطا در هنگام دسترسی به متغیر قبل از ایجاد آن، برطرف کند:
{
hoistedVariable;
let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization
این خطا با خطای "hoistedVariable is not defined" که ممکن است هنگام تلاش برای دسترسی به یک متغیر اعلام نشده انتظار داشته باشید متفاوت است. از آنجا که جاوا اسکریپت متغیر را افزایش داده است، آگاه است که متغیر در محدوده داده شده ایجاد می شود. با این حال، به جای اینکه آن متغیر را قبل از اعلان آن با مقدار undefined
در دسترس قرار دهد، مفسر خطا میکند. متغیرهای اعلام شده با let
یا const
(یا class
) گفته می شود که در یک "منطقه مرده زمانی" ("TDZ") از ابتدای بلوک محصور خود تا نقطه ای از کد که متغیر در آن اعلان می شود وجود دارند.
منطقه مرده زمانی رفتار let
را برای نویسندگان بصری تر از var
می کند. همچنین برای طراحی const
حیاتی است. از آنجایی که ثابت ها را نمی توان تغییر داد، ثابتی که در بالای محدوده آن قرار می گیرد و مقدار ضمنی undefined
به آن داده می شود، نمی تواند با مقدار معنی دار مقداردهی اولیه شود.
درک خود را بررسی کنید
با چه نوع شخصیت هایی می توانید یک شناسه را شروع کنید؟
کدام روش ترجیحی برای اعلام متغیری است که مقدار آن در هر زمان قابل تغییر است؟