علی ظفرامیلی
علی ظفرامیلی
خواندن ۴ دقیقه·۴ سال پیش

بررسی مفاهیم hoisting و closures در جاوا اسکریپت

برای متوجه شدن شیوه ­کار hoisting و closures در زبان جاوا اسکریپت باید با مفهومی آشنا شویم، تحت عنوان execution context، این مفهوم از شیوه اجرای برنامه ها در زبان جاوا اسکریپت گرفته می شود. زبان جاوا اسکریپت به عنوان یک زبان مفسری رفتار متفاوتی هنگام اجرای برنامه­ ها با زبان های دیگر برنامه ­نویسی دارد. این رفتار عبارت است از دو مرحله­ ی اساسی که مجموع آن را تحت عنوان ذکر شده می­شناسیم و مراحل آن عبارت است از :

1. Creation phase

2. Execution phase

در فاز اول یا فاز creation phase موتور جاوا اسکریپت که عموما روی مرورگر وجود دارد (در برنامه­ های front-end) مسئولیت ساخت global object و محتوای this پیش از اجرای برنامه است و در این مرحله از بالا تا پایین قطعه کد پیمایش شده و به ازای تمام محتوایی که نیاز به حافظه دارد (مانند متغیر یا توابع و ...) تخصیص حافظه صورت میگیرد و مقادیر تمام متغیر ها برابر با undefined قرار میگیرد، در واقع اگر دستوری داشته باشیم به طور مثال

const a = 2;

این متغیر با نام a، در فاز اول، مقدار 2 را نگرفته و صرفا حافظه ی مورد نیاز برای آن تخصیص داده شده و به صورت موقت مقدار اولیه آن برابر با undefined قرار میگیرد و در فاز دوم یا execution phase مقدار تخصیص داده شده به آن که 2 است را به آن نسبت می­دهیم و مسئله­ ی حائز اهمیت برای ما در فاز دوم این است که بدانیم دستورات به صورت خط به خط از بالا به پایین اجرا می شود.

تا بدین­جا میتوانیم عمل hoisting را توضیح بدهیم، تصور کنید برنامه ای داشته باشیم که در آن در خط اول متغیری را لاگ میگیریم و در خط دوم آنرا تعریف و مقدار دهی می کنیم. خروجی این برنامه undefined خواهد بود و با توضیحات پیشین میتوانیم نتیجه بگیریم که دلیل آن این است که در فاز creation phase این متغیر مقدار undefined میگیرد و در فاز دوم که برنامه خط به خط اجرا می شود، اول به دستور لاگ میرسد و مقدار undefined را چاپ می کند و در خط دوم تازه مقداری که ما به آن اختصاص دادیم را می­گیرد.

نکته ­ای که در این مرحله اهمیت دارد این است که بدانیم باور غلطی در این باره میان برنامه نویسان وجود دارد که بعضا معتقد هستند، جاوا اسکریپت تعریف متغیر ها را به صورت فیزیکی به اول برنامه منتقل می کند، این باور غلط است زیرا پیش از دو فاز ذکر شده موتور جاوا اسکریپت پیش پردازشی نداشته و اصطلاحا preprocess انجام نمی دهد، عمل hoisting صرفا بخاطر نوع ترجمه یا تفسیر کد های برنامه نویس در مرحله اجرا اتفاق می افتد و تغییر فیزیکی در کد اتفاق نمی افتد.

حال به بررسی مفهوم closures می پردازیم، پیش ­تر در مورد وظایف موتور جاوا اسکریپت در فاز creation صحبت کردیم که وظیفه­ی آن ساخت global object و this است. اتفاقی که هنگام call یا invoke شدن هر تابع می­افتد، این است که execution context جدیدی ساخته شده، حال پشته­ای را متصور بشوید که در آن global execution context را پیش­تر در آن قرار داده­ایم، با به وجود آمدن یک execution context محلی جدید به ازای فراخوانی یک تابع به وجود می­آید که آن را در پشته، بر روی آیتم قبلی قرار می­دهیم. در اینجا موتور جاوا اسکریپت علاوه بر وظایف پیشین خود، وظیفه­ی دیگری را به عهده می­گیرد و آن افزودن داده ­های محیط outer environment به تابع فراخوانی شده است. Outer environment یا محیط خارجی به تمام کدهایی گفته می­شود که خارج از "تعریف" تابع مذکور قرار دارد. دقت کنید که در اینجا اهمیتی ندارد که ما تابع را کجا فراخوانی کرده­ایم و محیط خارجی صرفا به محتوای scope ای محدود می­شود که تابع در آن "تعریف" یا declare شده است. به این شیوه­ی در نظر گرفتن محیط خارجی که وابسته به نحوه نگارش کدنویسی ما است، اصطلاحا lexical environment هم گفته می­شود. با این تعاریف گفته شده حال می­توانیم درک کنیم که closure ها چگونه کار می­کنند، اگر به این نکته توجه کنیم که زمانی که ما در هر scope از متغیری استفاده می­کنیم، جاوا اسکریپت ابتدا در execution context خود به دنبال آن متغیر می­گردد، اگر این متغیر در این execution context وجود نداشت، به رفرنسی که به صورت lexical از محیط خارجی خود دارد مراجعه کرده و به دنبال متغیر می­گردد، این عمل مراجعه به رفرنس قبلی برای یافتن مقدار یک متغیر تا زمانی ادامه پیدا می­کند که یا مقدار پیدا بشود، و یا به global execution context برسیم. در صورتی که در مرحله ­ی آخر هم مقداری برای متغیر یافت نشد، مقدار آن undefined خواهد شد.
خوشحال میشم نظرتونو در مورد این نوشته بدونم.

javascriptClosureshoistingexecution contextprogramming
شاید از این پست‌ها خوشتان بیاید