🔎 Lexical Scope در جاوا اسکریپت چیست؟
دامنه واژگانی یا دامنه استاتیک چیزی است که در طول سفر جاوا اسکریپت خود بارها درباره آن خواهید شنید و درک معنای دقیق آن مهم است.
اگر قبلاً این کار را نکردهاید، حتماً پست من در مورد اعلانهای متغیر را نیز بخوانید تا متوجه شوید که محدودهبندی و همچنین زمینه اجرا چگونه کار میکند، زیرا این به شما کمک میکند تا دامنه واژگانی را خیلی سریعتر درک کنید (که در آنجا به طور خلاصه توضیح میدهم).
دامنه چیست؟
Scope در جاوا اسکریپت به در دسترس بودن متغیرها یا توابع در قسمت های مختلف کد اشاره دارد. قطعات کد به معنای بلوک یا بخشی از کد است که در آن متغیرها یا توابع وجود دارد.
تصور کنید که شما متغیر هستید. آپارتمان شما که در آن زندگی می کنید محدوده شخصی شماست. منطقه ساختمانی که در آن زندگی میکنید اما خارج از آپارتمانتان نیز حوزه دیگری است، اما دیگر تنها محدوده شما نیست، زیرا متغیرهای مختلف، درست مانند شما، این محدوده را به اشتراک میگذارند (مثلاً آسانسور). محدوده دیگری که شامل محدوده ساختمان یا محدوده آپارتمان است می تواند خیابانی باشد که ساختمان در آن قرار دارد. در نتیجه محدوده آپارتمان شما از محدوده خیابان جدا می شود و هر اتفاقی در آپارتمان شما می افتد در آپارتمان شما می ماند!
مثال ساده دیگر یک جعبه در یک جعبه در یک جعبه در یک جعبه است که هر جعبه محدوده خاص خود را دارد.
انواع دامنه
یک جعبه در یک جعبه در یک جعبه مثال را به خاطر دارید؟ اولین کادر در این مثال محدوده جهانی است، کادر بعدی داخل آن محدوده تابع و کادر دیگر داخل کادر دوم محدوده بلوک است.
هر کلمه کلیدی متغیر بسته به دامنه کار متفاوتی دارد. برخی از متغیرها هنوز می توانند خارج از محدوده ای که در آن قرار دارند قابل دسترسی باشند در حالی که برخی دیگر در داخل اسپیکر گیر کرده اند و شما نمی توانید خارج از محدوده آنها به آنها دسترسی پیدا کنید.
گستره جهانی
دامنه جهانی یک محدوده برتر است و دامنه از کجا شروع می شود. این محیطی است که برای تمام قسمت های دیگر کد قابل مشاهده است. به عنوان مثال، وقتی شروع به ایجاد متغیرهای مختلف در بالای فایل js خود می کنید، این متغیرها سراسری هستند.
محدوده عملکرد
محدوده تابع محیط تابع است. هنگامی که یک متغیر در داخل تابع ایجاد می شود، می گوییم تابع scoped است. این بدان معنی است که این متغیر خارج از محدوده تابع قابل دسترسی نیست. اگرچه هر تابع یک محدوده محلی نیز دارد. یکی همچنین می تواند یک تابع در یک تابع دیگر و در یک تابع دیگر داشته باشد. تابع بسیار بالا دامنه خود را دارد، تابع دیگری در داخل نیز محدوده خود را دارد، محدوده محلی، و تابع سوم در داخل تابع دوم محدوده محلی خود را خواهد داشت.
محدوده را مسدود کنید
Block scope سومین محیط scope است که تا زمانی که این متغیر دارای block-scope است، اجازه نمی دهد متغیرهای ایجاد شده از محدوده آن خارج شوند.
محدوده بلاک کد داخل شرایط if-else، عبارات سوئیچ یا حلقه هایی مانند for و while است.
زنجیره دامنه چیست؟
همانطور که از نام آن پیداست زنجیره ی scope زنجیره ای از محدوده است! 🤡 مثال مربوط به توابع داخل توابع را به خاطر دارید؟ بیایید بگوییم، ما سعی میکنیم متغیری را در داخل عمیقترین تودرتوی تابع، console.log کنیم. موتور جاوا اسکریپت محدوده محلی را که لاگ کنسول فراخوانی شده است بررسی می کند. اگر متغیر در آنجا وجود داشته باشد، محدوده محلی کلاه را بررسی می کند. اگر آنجا نباشد، به نزدیکترین تابع می رود و وجود متغیر را در آنجا بررسی می کند.
اگر دوباره چیزی پیدا نشد، در صورت وجود، به تابع بالایی بعدی میرود و بررسی میکند که آیا متغیر مورد نیاز وجود دارد یا خیر. این فرآیند جستجو، زنجیره دامنه نامیده می شود، بنابراین فرآیند “جستجو” در زنجیره دامنه هایی است که به یکدیگر متصل هستند.
بیایید تجسم کنیم که محدوده دقیقاً چگونه در کد بالا کار می کند.
در کد بالا، زمانی که ParentFunction را در داخل آن فراخوانی می کنیم، یک متغیر اعلام شده و سپس innerFunction نامیده می شود. در داخل innerFuntion دوباره یک متغیر را اعلام می کنیم و تابع دیگری به نام innerInnerFunction را فراخوانی می کنیم، جایی که می خواهیم متغیرهای مختلف را به صورت کنسولی ثبت کنیم. اولین کنسول باید متغیر اعلام شده در محدوده جهانی را ثبت کند. با این حال، موتور جاوا اسکریپت قرار نیست متغیر را مستقیماً از دامنه جهانی بگیرد. ابتدا محدوده محلی را بررسی می کند و سعی می کند آن را در آنجا پیدا کند. به عبارت دیگر، به دنبال متغیری در نزدیکترین ناحیه می گردد و تنها پس از آن حرکت می کند. در مورد ما، به تابع بعدی میرود و در آنجا جستجو میکند، سپس دوباره بالا میرود و دوباره جستجو میکند تا به محدوده جهانی برسد و متغیر مورد نیاز ما را پیدا کند.
دقیقاً همین فرآیند در گزارش کنسول دوم، برای parentFunctionVariable اتفاق میافتد. تا زمانی که مکان ایجاد این متغیر را پیدا کند، دامنه را بالا می برد.
دامنه واژگانی چیست؟
وقتی نوبت به زنجیره اسکوپ میرسد، تابع داخلی همیشه میتواند به محدوده عملکرد خود دسترسی داشته باشد، بنابراین زنجیره دامنه میتواند به سمت بالا حرکت کند – از فرزند به والدین.
با این حال، تابع والد ممکن است به تابع داخلی دسترسی نداشته باشد، بنابراین دامنه تابع نمی تواند به سمت پایین برود، همیشه فقط بالا می رود!
این فرآیند یا توانایی تابع برای دسترسی به متغیرهای والد را دامنه واژگانی می نامند. به عبارت دیگر، تابع فرزند درونی همیشه از نظر لغوی به والد خود متصل است و همیشه می تواند به متغیرهای آن دسترسی داشته باشد.
دامنه واژگانی در این مورد محدوده ای است که در آن متغیرهای هدف ایجاد شده اند و فراخوانی نشده اند. شما می توانید یک متغیر را در یک مکان فراخوانی کنید، اما آن را در مکان دیگری، به عنوان مثال، تابع والد، اعلام کنید.
چرا زنجیره دامنه نمی تواند به سمت پایین برود؟
همانطور که اشاره کردم دامنه واژگانی فقط در مورد زنجیره دامنه بالا و بالا رفتن است. اگر قبلاً در مورد زمینه اجرا خوانده اید، یاد گرفته اید که وقتی متغیرها را ایجاد می کنیم، آنها در داخل شی متغیر ذخیره می شوند تا بتوانیم برای استفاده بعدی به آنها ارجاع دهیم. همچنین، هنگامی که متغیرها را ایجاد می کنید، دو نوع زمینه وجود دارد که در آن ذخیره می شوند. آنها یا به صورت سراسری ذخیره می شوند یا در زمینه اجرای تابع ذخیره می شوند. زمینه اجرای تابع زمانی ایجاد می شود که یک متغیر در داخل یک تابع ایجاد می کنید – بنابراین هر تابع زمینه خاص خود را دارد.
وقتی متغیرهایی را در داخل یک تابع ایجاد میکنید، همیشه نمیتوانید در خارج از آن به آنها دسترسی پیدا کنید، زیرا دارای محدوده تابع هستند.
سعی کنید کد بالا را تحلیل کنید و از مثال قبلی استفاده کنید. فکر میکنید در این مورد چه اتفاقی میافتد اگر بخواهیم همه متغیرها را با کنسول وارد کنیم؟
چیزی که من این بار تغییر دادم این است که مانند قبل یک متغیر جهانی دارم اما دو متغیر دیگر را به دامنه جهانی اضافه کردم که در داخل تابع نیز تکرار می شوند. در مرحله بعد، من همچنین سعی می کنم متغیری را که در داخل تابع ایجاد کرده ام به صورت کنسولی ثبت کنم.
بیایید سعی کنیم بفهمیم اینجا چه خبر است. وقتی میخواهیم متغیر log را که خارج از تابع اعلان شده است کنسول کنیم، همه چیز خوب کار میکند، اما وقتی نوبت به آخرین گزارش کنسول میرسد، خطا میدهد. چرا؟ زیرا هیچ محدوده بالایی وجود ندارد و متغیر مورد نیاز ما در داخل تابع است. به همین دلیل است که یک ReferenceError دریافت می کنیم.
نتیجه
در نتیجه، دامنه واژگانی در جاوا اسکریپت به توانایی یک تابع درونی برای دسترسی به متغیرها و توابع تعریف شده در تابع بیرونی یا تابع والد آن اشاره دارد، اما نه برعکس. این به این دلیل است که زنجیره اسکوپ فقط می تواند از کودک به والدین به سمت بالا حرکت کند و نه به سمت پایین. تابع درونی همیشه از نظر لغوی به تابع والد خود متصل است و به آن امکان می دهد به متغیرها و توابع خود دسترسی داشته باشد که در زمان ایجاد تابع درونی در محدوده والد اعلام شده بودند.