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

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

برنامه نویسان کم تجربه ای که ابتدا به جاواسکریپت کوچ می کنند در ابتدا ممکن است بسیاری از مفاهیم آن را عمیق درک نکنند. به همین منظور تصمیم گرفتم که در این پست به صورت کاملا جامع مفاهیم scope در جاواسکریپت رو مورد بحث و بررسی قرار بدم و امیدوارم که در نهایت بتونم رضایت شما مخاطبان عزیز رو جلب کنم.

به دلیل کمبود منابع فارسی و همچنین نبود سرفصل هایی به جا و مناسب، اغلب درک scope در جاواسکریپت رو بسیار کوتاه و در حد چند مثال بررسی می کنند اما در این پست من قصد دارم کامل ترین مفاهیمی که شامل درک scope در جاواسکریپت می شوند رو طبق سرفصل زیر با شما عزیزان مورد بحث و بررسی قرار بدم پس با من همراه باشید 🙂

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

    • scope چیه؟
    • چرا این مفهوم به وجود آمده است؟
    • درک scope در جاواسکریپت
    • بررسی انواع scope
    • ظهور context
    • Execution Context
    • مفهوم Lexical Scope

scope چیه؟

به محدوده ی قابل دسترسی متغیر ها ، توابع و اشیا ( که از این به بعد قرارداد می کنیم اونها رو همون object بنامیم ) میگن scope

در واقع زمانی که کد شما در مرحله ی runtime قرار داره توسط مفهومی به نام scope محدوده ی قابل دسترسی هر متغیر ، تابع و object برای دیگر قسمت های کد تعیین و مشخص میشه.

چرا این مفهوم به وجود آمده است؟

در حقیقت این مفهوم در اکثر زبان هایی که type-safe هستند مشابه و به یک شکل وجود داره اما زبان جاواسکریپت به دلیل اینکه Encapsulate بودن اون به قدرت زبان هایی مثل جاوا و یا C++ نیست  این مفهوم در واقع به طور کاملا ضعیفی جایگزین Encapsulate بودن شده ! ( حالا وقتی میگیم جاواسکریپت زبان OOP نیست ممکنه خیلی ها تحویل نگیرن حرفمون رو ولی اینجاها ثابت میشه 😀 )

پس تا اینجا یک دلیلش امنیت و قابل دسترسی نبودن همه ی کدها در همه جای برنامه است ، قابلیت دیگر میشه به دیباگ کردن راحت تر و حتی نام گذاری پویاتر اشاره کرد.

درک scope

در جاواسکریپت 2 نوع scope داریم که از انواع کلی scope ها به شمار میان و Global Scope و Local Scope رو شامل میشن.

باید توجه داشته باشیم که تنها با فراخوانی یک تابع، scope مربوط به اون تابع و متغیرها و زیرتوابع و object ها ساخته میشه.

Global Scope

زمانی که شروع می کنید در یک داکیومنت جاواسکریپت کد بنویسید شما دارید در Global Scope کدنویسی می کنید.

فقط یک Global Scope در جاواسکریپت وجود داره و هر چیزی که در Global Scope تعریف بشه توسط تمامی توابع زیرین و object ها در دسترس خواهد بود و همچنین خارجی ترین قسمت یک برنامه ی شما Global Scope به شمار میاد.

به کد زیر توجه کنید:

خب متغیر name در بالا به صورت Global تعریف شده پس باید توسط تمام توابع زیرین و object ها قابل دسترسی باشه بیایم باهم ببینیم 🤔

 

Local Scope

متغیر هایی که درون توابع قرار میگیرند اصطلاحا محدود به Local Scope هستند. این به این معنی است که تنها در محدوده محلی مورد نظر در دسترس خواهند بود.

به عبارت بهتر شما می توانید متغیر های هم نام را در scope های متفاوت به کار ببرید. زیرا آن ها در scope های دیگر در دسترس نخواهند بود.

بهتره با هم یه مثال ببینیم :

 

Block Statement

بلاک هایی مانند if…else و swtich و for و while بر خلاف توابع یک scope جدید تولید نمی کنند و در واقع در scope قبلی ای که قرار داشتند قرار می گیرند.

بعد از ظهور EMCAScript 6 در سال 2015 دو keyword جدید برای تعریف متغیر ها معرفی شدند که let و const نام داشتند.

این دو keyword می توانند به جای var استفاده شوند.

بر خلاف var ، کلمه کلیدی های let و const در Block Statement ها همانند یک Local Scope یک Scope جدید ساخته و رفتار مشابهی دارند.

Global Scope در تمام طول اجرای برنامه در دسترس خواهد بود و Local Scope تنها در زمانی که تابع مربوط به آن فراخوانی شده و در حال خروجی گرفتن می باشد ، در دسترس خواهد بود.

Context

برنامه نویسانی که به تازگی کار با js رو شروع می کنند اصولا در مفهوم context و scope دچار مشکل می شوند. اما این دو کاملا مفاهیم جداگانه ای هستند. scope به محدوده ی قابل دسترسی متغیر ها و توابع و object ها اشاره دارد در حالی که context به مقدار this در همان scope اشاره دارد.

ما می تونیم مقدار context رو تغییر بدیم و بعدا در موردش صحبت خواهیم کرد اما بیاید یک مثال از context ببینیم:

اگر scope ، بخشی از یک object باشه context به اونobject که در scope اون قرار گرفته اشاره می کنه.

در مورد (new User).logName( این یک راه میانبر و کوتاه هست برای instance گرفتن از کلاس User و سپس اجرا کردن logName که یکی از متدهای این Object هست.

یک چیزی که باید بدونید اینه که مقدار context در هنگامی که یک تابع رو با کلمه کلیدی this صدا می زنید کاملا متفاوت خواهد بود. به عنوان مثال تابع زیر رو در نظر بگیرید این تابع در حالت عادی اگر بدون new فراخوانی بشه مقدار this برابر خواهد بود با window اما…

 

Execution Context

برای رفع ابهام تمام موارد بالا که یاد گرفتیم قصد داریم یک مفهوم جدید رو معرفی کنیم که بهش میگن Execution Context

اگه بخوایم از لحاظ لغوی و معنی بررسی کنیم که خب Execution به معنای اجرایی شدن ، انجام و اجرا هست و خب همراه با Context که بیاد به معنی اجرا شدن Context اشاره می کنه.

اما از لحاظ مفهوم ، Execution Context دقیقا به Scope اشاره می کنه و اصلا کاری با Context نداره 😃

پس شاید تعجب کنید که علت این نام گذاری چی بوده 🤔 که خب باید بگم این یه قرارداده و باید ازش پیروی کنیم 🤓

جاواسکریپت یک single-threaded language به حساب میاد بنابر این کد ها به صورت خط به خط اجرا می کنه و باقی task ها به صورت صف در Execution Context قرار میگیره !

همانطور که قبلا هم گفتیم مترجم جاواسکریپت زمانی که شروع به ترجمه کردن کد می کنه به صورت دیفالت اولین لایه کد شما رو در Global Scope قرار میده.و این Global Scope اولین context ای هست که در execution context اجرا میشه.

بعد از این ، هر تابع که صدا زده میشه (invocation) به صف execution context منتقل میشه و این عمل برای توابعی که درون توابع دیگر قرار دارند هم به همین شکل اتفاق میوفته.

هر تابع execution context مربوط به خودش رو داره و میسازه!

زمانی که مرورگر یک بار کدهای درون یک context رو انجام میده ، اون context مربوطه از استک execution context برداشته میشه و نشانگر وضعیت به parent context منتقل میشه.

مرورگر همیشه از درونی ترین سطح کد شما که در واقع بالاترین سطح execution context stack هست شروع به اجرای برنامه می کنه.

تنها یک Global Context در یک برنامه وجود داره در حالی که به تعداد توابع ما function context خواهیم داشت.

Execution Context Phases

دو فاز برای اجرا شدن وجود داره

  • فاز ساختن (Creation Phase)
  • فاز اجرا شدن کد (Code Execution Phase)

فاز ساختن (Creation Phase)

این اولین فاز اجرایی یک context محسوب میشه. در توضیح دقیق تر می تونم بگم زمانی که شما یک تابع رو صدا می زنید و اون تابع هنوز اجرا نشده سه تا عمل اتفاق میوفته :

  • ساخت یک Variable Object
  • ساخت یک زنجیره دسترسی (Scope Chain)
  • تنظیم مقدار this
ساخت یک Variable Object

در این مرحله تمامی متغیر ها و توابع و object ها درون یک Variable Object قرار می گیرند.

ساخت یک زنجیره دسترسی (Scope Chain)

در فاز اول scope chain بلافاصله بعد از variable object ساخته می شود و شامل variable object مربوط به execution context خودش و همچنین variable object های execution context والد هاش میشه. در واقع یک object ای هست که گروهی از object هاست.

همچنین بهتره بدونین که وقتی جاواسکریپت شروع به اجرای یک Execution Context می کنه ابتدا به سراغ درونی ترین توابع میره و سپس به سمت parent اون ها اصطلاحا jump می کنه به همون روشی که بالاتر خدمتتون عرض کردم.

یک مثال از یک Execution Context ببینیم :

 

فاز اجرا کردن کد (Code Execution Phase)

در این مرحله مقادیر به متغیر ها نسبت داده می شوند و در نهایت کد اجرایی خواهد شد.

Lexical Scope

آخرین مفهومی که در این پست قرار هست باهم بررسی کنیم Lexical Scope هست. Lexical به معنای واژگان ، لغوی ، لغت و مترادف این کلمات در نظر گرفته میشه و در کنار Scope مفهومی به نام Lexical Scope رو شکل میده که زمانی این مفهوم کارایی داره که ما مجموعه ای از توابع تو در تو داشته باشیم (Nested Function)  !

در این حالت درونی ترین تابع به تمام مواردی که در parent scope اش هست دسترسی کامل داره.

این به این معنی است که تابع فرزند به execution context تابع والد محدود هست.

گاها Lexical Scope رو به عنوان Static Scope هم ممکنه ببینید.

بهتره یه مثال ببینیم تا بهتر درک کنیم 🙂

با بیان Lexical Scope در واقع پا به دنیای Closure گذاشتیم که در یک پست به صورت کامل به بحث و بررسیش می پردازیم و بعد در اینجا لینک رو قرار خواهم داد.

اما فعلا در این حد نتیجه گیری کنید که متغیر هایی که نام یکسانی دارند و در توابع تو در تو قرار گرفته اند اولویت با درونی ترین تابع هست 🙂

خب امیدوارم که لذت برده باشید.

Share:

ارسال یک پاسخ

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

46 − = 37