همانطور که در عنوان قابل مشاهده است عبارت lexical scope از دو کلمه تشکیل شده. پس کار را با معرفی scope شروع کرده و سپس به توصیف وضعیتی که مشهور به lexical است بپردازم.
قطعه کد زیر را در نظر بگیرید.
var mahsool = 'pashmak'; function chap () { console.log(mahsool); } chap();
دلیل اینکه این کد عبارت «pashmak» را در کنسول چاپ میکند این است که جاوا اسکریپت وقتی به قصد اجرا وارد بدنه فانکشن chap میشود میبیند که چیزی به اسم mahsool میبایست به تابع console.log بدهد. پس جستجویی را برای یافتن آن آغاز میکند. این جستجو در چند محدوده اجرا میشود و به این محدودهها اصطلاحا scope گفته میشود. اولین scope طبیعتا در بدنه همین تابعی است در حال اجرای آن است (در اینجا فانکشن chap). مشخصا این جستجو موفقیت آمیز نخواهد بود. پس از این شکست، جاوا اسکریپت به دنبال پیدا کردن مقدار متغییر در محلی که تابع در آن صدا زده میگردد و این بار موفق میشود متغییر mahsool = 'pashmak' را بیابد و نهایتا آن را در کنسول چاپ کند.
به محدودههایی که سیستم در آنها به دنبال مقدار یک متغییر میگردد اصطلاحا Scope گفته میشود.
حال قطعه کد زیر را در نظر بگیرید.
function tashih_ba_daste_baste() { console.log( nomre ); // 9.75 } function tashih() { var nomre = 10; tashih_ba_daste_baste(); } var nomre = 9.75; tashih();
خب خروجی کد بالا ۹.۷۵ است! متاسفم. دلیل این مساله در استراتژی جاوا اسکریپت در انتخاب scope هاست. وقتی جاوا اسکریپت متد tashih را اجرا میکند، به فانکشن tashih_ba_daste_baste میرسد. مشخصا در اسکوپ این فانکشن هیچ خبری از متغییر nomre نیست. پس به سراغ جایی که اولین بار متد tashih در آن نوشته شده میرود و گم شده خویش را در آنجا مییابد (خط ۱۰ و ۱۱ - با تشکر از آقا محسن عزیز). به این سیاست اصطلاحا Lexical Scope گفته میشود.
در Lexical Scope در صورت پیدا نشدن متغییر در اسکوپ فعلی، اسکوپ بعدی جایی است که تابع در آنجا نوشته شده است.
قطعه کد زیر را در نظر بگیرید
function tashih_ba_daste_baaz() { console.log( this.nomre ); // 10 (na 9.75!) } function tashih() { this.nomre = 10; tashih_ba_daste_baaz(); } this.nomre = 9.75; tashih();
تبریک میگم! خروجی کد بالا ۱۰ است. اما چطور؟
جاوا اسکریپت در خصوص متغییر کلیدی this رفتار ویژهای اتخاذ میکند. چون this ژن خوبی دارد، وقتی در اسکوپ فعلی آن را پیدا نکند، به سراغ جایی که متد حاوی this را صدا زده میرود و از ایشان میپرسد: معذرت میخوام ایشون آقا زاده شما هستن؟ اگر جواب منفی بگیرد باز هم از پا نمینشیند و سراغ فانکشنهایی که آن فانکشنها را صدا زده اند میرود و القصه اینکار تا خود اسکوپ global ادامه پیدا میکند.
اسکوپ گلوبال (global scope) بالاترین سطحی است که جاوا اسکریپت برای پیدا کردن متغییرها به آنجا سر میزند. هر متغییری خارج از بدنه یک function تعریف شده باشد در سطح global قرار میگیرد. به عنوان مثال در محیط مرورگرها، آبجکت window یک متغییر در سطح گلوبال است.
پس در اینجا وقتی tashihe_ba_daste_baz هیچ تعریفی در خصوص this.nomre ندارد، کار جستجو در متد tashih دنبال میشود. در آنجا this.nomre = 10 دیده میشود و جستجو خاتمه مییابد و بقیه کار دنبال میشود. به این ترتیب است که سیاست Dynamic Scope در این کد اجرا میشود.
در Dynamic Scope در صورت پیدا نشدن یک متغییر، جستجو برای پیدا کردن آن در سلسله توابعی منجر به اجرا شدن این فانکنشن شدهاند، دنبال میشود.
در آینده نزدیک مطلبی در خصوص روشهای تشخیص مقدار this از روی کد خواهم نوشت.