Hoisting در جاوا اسکریپت – توضیح مفهوم به زبان ساده
Hoisting یکی از مفاهیم مهم در جاوا اسکریپت است که درک صحیح آن برای برنامهنویسان حرفهای ضروری است. Hoisting در جاوا اسکریپت به مکانیزمی در این زبان برنامه نویسی اشاره دارد که در آن اعلانهای متغیر و تابع قبل از اجرای کد به بالای «محدوده» (Scope) مربوطه خود خواهند رفت. در این مکانیسم، فرقی نمیکند که توابع و متغیرها در کجای کد اعلام میشوند. آنها به طور مؤثری به بالای دامنه یا محدوده خود منتقل خواهند شد، چه این محدودهها در سطح «سراسری» (Global) قرار بگیرند و چه در سطح محلی (Local) باشند، این انتقال اتفاق خواهد افتاد. عمل Hoisting در Javascript تنها برای اعلان متغیرها و توابع اعمال میشود که در آن تخصیص یا مقداردهی اولیه این موجودیتها در مکانهای اصلی در کد باقی میماند. در این مطلب از «مجله فرادرس»، مفهوم Hoisting در جاوا اسکریپت به صورت کامل پوشش داده خواهد شد.
در این مطلب از مجله فرادرس، ابتدا تعریف Hoisting را مرور میکنیم و میبینیم این پدیده به چه معناست. سپس به بررسی Hoisting برای متغیرها و توابع میپردازیم و مثالهایی را مرور میکنیم. در ادامه با ترتیب اولویت در اعلانهای جاوا اسکریپت و همچنین Hoisting برای کلاسها آشنا میشویم. در پایان نیز نکات کلیدی را جمعبندی میکنیم. پس اگر به جاوا اسکریپت علاقهمند هستید، حتما این مطلب را تا انتها مطالعه کنید.
تفاوت بین undefined و ReferenceError در جاوا اسکریپت
یکی از پیشنیازهای درک مفهوم Hoisting در جاوا اسکریپت، درک تمایز بین دو نوع خطای رایج در این زبان، یعنی «تعریف نشده» (undefined) و «خطای مرجع» (ReferenceError) است.
برای پرداختن به این موضوع توجه به مثال زیر در این رابطه اهمیت زیادی دارد.
1console.log(typeof variable);
خروجی کد بالا در کنسول مرورگر به صورت زیر است:
در زبان برنامه نویسی جاوا اسکریپت، زمانی که متغیری اعلان نشده باشد، در حین اجرا مقدار undefinedرا به خود اختصاص داده و به عنوان متغیری با نوع تعریف نشده طبقهبندی میشود. نکته دوم و قابلتوجه این بخش در کد زیر نهفته است.
1console.log(variable); // Output: ReferenceError: variable is not defined
حال خروجی کد بالا این بار به صورت زیر است:
در جاوا اسکریپت، اگر تلاشی برای دسترسی به متغیری انجام شود که قبلاً اعلام نشده است، خطای مرجع ReferenceErrorایجاد خواهد شد. رفتار جاوا اسکریپت هنگام مدیریت متغیرها به دلیل وجود Hoisting پیچیده میشود. در بخشهای آتی این مفهوم به صورت کامل بررسی میشود.
Hoisting در جاوا اسکریپت چیست؟
Hoisting در جاوا اسکریپت فرآیندی است که طی آن اعلانهای متغیر و تابع در مرحله آمادهسازی کد به بالای محدوده مربوطه خود منتقل میشوند. در این رابطه متغیرهای اعلان شده با کلمه کلیدی «Var» به بالای محدوده خود منتقل شده و با «Undefined» مقداردهی اولیه خواهند شد. از طرفی دیگر آنهایی که با استفاده از کلمات کلیدی «Let» و «Const» اعلان شوند تا زمانی که به طور صریح مقداری به آنها اختصاص داده نشود، بدون مقدار اولیه باقی میمانند.
همچنین اعلانهای تابع نیز به طور کامل به بالای محدوده خود منتقل میشوند که این ویژگی به آنها اجازه میدهد قبل از تعریف قابل فراخوانی باشند. به زبانی ساده مکانیسم Hoisting ارجاع و استفاده از متغیرها و توابع را قبل از اعلان واقعی آنها در کد تسهیل میکند. در ادامه به صورت عملی به بررسی این موضوع پرداخته خواهد شد.
Hoisting در جاوا اسکریپت برای متغیرها
تصویر زیر چرخه حیات متغیرهای جاوا اسکریپت را ترسیم میکند و در مورد ترتیب اعلان متغیر و مقداردهی اولیه، آگاهی نسبی به برنامهنویس میدهد.
با این وجود، به دلیل قابلیت جاوا اسکریپت برای اعلان و مقداردهی اولیه متغیرها به طور همزمان، روش رایج اعلان متغیر شامل الگوی زیر میشود:
1var a = 100;
توجه به این نکته مهم است که در پشت صحنه، جاوا اسکریپت به سختی اعلان متغیر و سپس مقداردهی اولیه را انجام میدهد. همانطور که قبلاً تأکید شد، همه اعلانهای متغیر و تابع تا بالای محدوده مربوطه خود بالا میروند یا به اصطلاح Hoisting در جاوا اسکریپت انجام خواهد شد. همچنین اعلانهای متغیر قبل از اجرای هر کدی پردازش میشوند.
با وجود همه اینها و توجه به نکات گفته شده نوعی تضاد متمایز در مورد متغیرهای اعلان نشده وجود دارد. آنها تا زمانی که کد مربوط به خودشان اجرا نشود، وجود نخواهند داشت. در نتیجه، هنگامیکه مقداری به متغیری اعلان نشده اختصاص داده میشود، به طور ضمنی به عنوان نوعی متغیر سراسری در طول اجرای آن تخصیص، تولید میشود. این بدان معناست که همه متغیرهای اعلان نشده به عنوان متغیرهای سراسری عمل میکنند. برای نشان دادن این رفتار توجه به کد زیر بسیار مهم است:
1function hoist() {
2 a = 20;
3 var b = 100;
4}
5
6hoist();
7
8console.log(a);
9/*
10Accessible as a global variable outside hoist() function
11Output: 20
12*/
13
14console.log(b);
15/*
از آنجا که این یکی از ویژگیهای خاص جاوا اسکریپت در مدیریت متغیرها است، توصیه میشود که متغیرها قبل از استفاده اعلان شوند، صرفنظر از اینکه آنها به محدوده تابع یا محدوه سراسری تعلق دارند، این عمل به طور مشخص نشان میدهد که چگونه مفسر باید این متغیرها را در طول زمان اجرا مدیریت کند.
متغیرها در ES5
برای بهتر روشن شدن قضیه Hoisting در جاوا اسکریپت در این بخش به بررسی نحوه تعریف متغیرها در جاوا اسکریپت «ES5» خواهیم پرداخت. محدوده متغیری که با استفاده از کلمه کلیدی varاعلان میشود، شامل زمینه فعلی اجرای آن است. این زمینه میتواند تابعی محصور کننده باشد. همچنین میتواند برای متغیرهایی که خارج از تابع اعلان شدهاند، محدوده سراسری باشد.
Hoisting در متغیرهای سراسری
برای درک عمل Hoisting در متغیرهای سراسری توجه به مثال زیر در آغاز کار مهم است:
1console.log(hoist); // Output: undefined
2
3var hoist = 'The variable has been hoisted.';
در کد بالا در حالی که ممکن است به دلیل متغیر تعریف نشده انتظار خطای مرجع را داشته باشیم، خروجی در واقع undefinedاست. امکان دارد برای کاربر سؤال باشد که چرا این اتفاق میافتد؟ در این مورد میتوان گفت که عمل Hoisting در جاوا اسکریپت اتفاق افتاده است و اساساً مثال فوق به صورت زیر تفسیر میشود.
1var hoist;
2
3console.log(hoist); // Output: undefined
4hoist = 'The variable has been hoisted.';
در نهایت از مثال فوق میتوان نتیجه گرفت که متغیرها را قبل از اعلان آنها میتوان به کار گرفت. با این حال، در این زمینه باید احتیاط کرد زیرا متغیرهای Hoistedبا مقدارundefinedمقداردهی اولیه میشوند. در بهترین حالت، توصیه میشود که متغیرها قبل از استفاده از آنها اعلان و مقداردهی اولیه شوند.
Hoisting برای متغیرهای محدوده تابع
همانطور که در بخش قبل نشان داده شد، متغیرهای درون محدوده سراسری در بالای آن محدوده قرار میگیرند. حال در این بخش عمل Hoisting در جاوا اسکریپت برای متغیرهای محدوده تابع بررسی خواهند شد. برای این هدف توجه به مثال زیر بسیار مهم است.
1function hoist() {
2 console.log(message);
3 var message = 'Hoisting is all the rage!';
4}
5
6hoist();
مفسر جاوا اسکریپت کد بالا را به صورت زیر میبیند:
1function hoist() {
2 var message;
3 console.log(message);
4 message = 'Hoisting is all the rage!';
5}
6
7hoist(); // Output: undefined
همانطور که قابل مشاهده است، خروجی undefinedخواهد بود. اعلان متغیر var messageکه به محدوده تابع hoist()تعلق دارد، در بالای آن تابع قرار میگیرد. برای فرار از این دام، نوعی رویکرد محتاطانه این است که متغیر قبل از استفاده از آن اعلان و مقداردهی اولیه شود. مانند مثال زیر:
1function hoist() {
2 var message = 'Hoisting is all the rage!';
3 return message;
4}
5
6hoist(); // Output: Hoisting is all the rage!
حالت سخت گیرانه در جاوا اسکریپت چیست؟
به لطف نوعی ویژگی در نسخه ES5 جاوا اسکریپت که به عنوان «حالت سختگیرانه» (Strict Mode) شناخته میشود، میتوان هنگام اعلان متغیرها احتیاط بیشتری به خرج داد. با استفاده از این حالت سختگیرانه کاربر با جاوا اسکریپت قابل تنظیمتری سروکار خواهد داشت و در این حالت جاوا اسکریپت اجازه استفاده از متغیرها را قبل از اعلان رسمی آنها نمیدهد. Strict Mode در جاوا اسکریپت مزیتهای زیادی دارد که از مهمترین آنها میتوان موارد زیر را نام برد:
- حذف خطاهای نادیده گرفتهشده یا خطاهای خاموش: این حالت برخی از خطاهای جاوا اسکریپت نادیده گرفتهشده را به خطاهای پرتاب صریح تبدیل میکند که سپس به سرعت به وسیله مفسر ارائه میشود.
- بهینهسازی موتور پیشرفته: این حالت Strict Mode خطاهایی را تصحیح میکند که در غیر این صورت ممکن است موتورهای جاوا اسکریپت از انجام کارآمد بهینهسازیها ناتوان باشند.
- پیشگیری از خطاهای نحوی در آینده: این حالت در جاوا اسکریپت ساختارهای نحوی خاصی را که به طور بالقوه میتوانند در نسخههای بعدی جاوا اسکریپت تعریف شوند، مجاز نمیداند و در نتیجه مشکلاتی پیش نخواهد آمد.
نحوه فعال سازی حالت سخت گیرانه در جاوا اسکریپت
برای فعال کردن حالت سخت، دستورالعمل زیر باید در ابتدای فایل یا تابع مدنظر قرار بگیرد: