با سلام، در این قسمت از سری آموزشی برنامه نویسی جاوا اسکریپت قصد داریم در رابطه با مبحث scope صحبت کنیم
احتمالا گوشتان به بحث Scope خورده است.
ابتدا باید بگویم scope مربوط به بحث accessibility (دسترسی) است. کلمه ی accessibility به معنی دسترسی و کلمه ی visibility به معنی "پدیداری" یا پدیدار بودن است اما در برنامه نویسی معنی یکسانی دارند.
هر دوی این کلمات به این مبحث اشاره می کنند که یک متغیر یا عنصر دیگر در سورس کد، از کدام قسمت ها قابل دسترسی باشد. آیا اگر متغیری در سورس کد من تعریف شد، می توانم از هر جای سورس کد به آن دسترسی داشته باشم؟
در جاوا اسکریپت دو نوع scope داریم:
این دو مورد در فارسی به شکل های مختلفی ترجمه شده اند؛ به طور مثال local scope به صورت "دامنه ی محلی" و global scope به صورت "دامنه ی سراسری" ترجمه شده اند.
یکی از مهم ترین مباحث مربوط به scope، بحث توابع است. در جاوا اسکریپت هر تابع یک scope جداگانه تعریف می کند، بنابراین متغیرهایی که در یک تابع تعریف شوند یک scope از نوع local نسبت به آن تابع پیدا می کنند. یعنی چه؟ بگذارید نشانتان دهم ... .
اگر متغیری در یک تابع تعریف شود، دامنه اش نسبت به آن تابع محلی خواهد ماند و به اصطلاح می گوییم چنین متغیر هایی، Function scope (دامنه ی تابعی) دارند. معنی ساده ی آن این است متغیر مورد نظر ما تنها از داخلِ خودِ تابع در دسترس خواهد بود.
به مثال زیر توجه کنید:
<!DOCTYPE html> <html> <body> <h2>JavaScript Scope</h2> <p>Outside myFunction() carName is undefined.</p> <p id="demo1"></p> <p id="demo2"></p> <script> myFunction(); function myFunction() { var carName = "Volvo"; document.getElementById("demo1").innerHTML = typeof carName + " " + carName; } document.getElementById("demo2").innerHTML = typeof carName; </script> </body> </html>
در مثال بالا ابتدا تابعی به نام myFunction تعریف می کنیم. سپس داخل این تابع، متغیری به نام carName تعریف کرده و مقدارش را برابر با رشته ی "Volvo" قرار می دهیم. حالا با دستور typeof و مقدار خود تابع می خواهیم ابتدا نوع داده ای که داخل تابع است را نمایش دهیم و سپس مقدارش را. در کد بالا دو دستور داریم که نقطه ی اصلی بحث هستند:
document.getElementById("demo1").innerHTML = typeof carName + " " + carName;
document.getElementById("demo2").innerHTML = typeof carName;
دستور اول عنصری با آیدی demo1 را می گیرد و نوع داده ی متغیر carName را به همراه مقدارش در آن می ریزد اما دستور دوم سعی می کند این کار را در demo2 انجام دهد. خروجی مثال ما به این شکل خواهد بود:
string Volvo
undefined
مشاهده ی خروجی کد در ادیتور آنلاین جاوا اسکریپت
چرا دستور اول مقدار "string Volvo" را تولید کرده است اما دستور دوم می گوید چنین متغیری تعریف نشده است (undefined)؟ به این دلیل که دستور اول در خودِ تابع نوشته شده است و همانطور که گفتیم اگر متغیری در تابعی تعریف شود تنها از درونِ خودِ آن تابع قابل دسترسی خواهد بود اما دستور دوم بیرون از تابع قرار دارد و اصلا روحش هم خبر ندارد متغیری به این نام وجود دارد.
سوال: چرا در مثال بالا، تابع را صدا زده ایم؟
پاسخ: بله، اگر دقت کرده باشید تابع myFunction را پس از تگ های <script> صدا زده ایم:
myFunction();
دلیل آن این است که متغیر های محلی (Local variables) زمانی ایجاد می شوند که تابع صدا زده شود و پس از اجرای تابع حذف می شوند. بنابراین اگر تابع را صدا نزنید چنین متغیری اصلا وجود نخواهد داشت. در واقع اگر تابع myFunction را صدا نزنیم نه متغیری ساخته می شود نه دستور های داخل آن اجرا می شوند بنابراین در چنین حالتی تنها خروجی ما عبارت undefined خواهد بود.
برای امتحان کردن این موضوع می توانید به ادیتور آنلاین جاوا اسکریپت بروید و قسمت فراخوانی این تابع را حذف کنید.
نکته: ممکن است پس از اعمال هر گونه تغییر در کد ها، نیاز باشد از سمت راست و بالا دکمه ی Run with JS را بزنید تا کد جدید یک بار اجرا شود و بتوانید تغییرات را مشاهده کنید.
نکته: در جاوا اسکریپت، اشیاء و توابع نیز متغیر به حساب می آیند. بر این اساس می توان گفت scope ها سطح دسترسی متغیر ها (variables)، اشیاء (objects) و توابع (functions) را تعیین می کنند.
باید به یاد داشته باشید که اگر مقداری خاص را به متغیری نسبت دهید که به صورت صریح declare نشده باشد، به شکل خودکار تبدیل به یک متغیر سراسری (GLOBAL variable) می شود.
در مثال زیر یک متغیر سراسری به نام carName
ساخته می شود، اگر چه آن را داخل یک تابع تعریف کرده ایم:
<!DOCTYPE html> <html> <body> <p>If you assign a value to a variable that has not been declared, it will automatically become a GLOBAL variable:</p> <p id="demo"></p> <script> myFunction(); // را یک متغیر سراسری می دانند carName کد های این قسمت document.getElementById("demo").innerHTML = "I can display " + carName; function myFunction() { carName = "Volvo"; } </script> </body> </html>
توضیح کد بالا:
با اینکه متغیر carName داخلِ تابع تعریف شده است، باز هم از بیرون قابل دسترس بوده و خروجی "I can display Volvo" را نمایش می دهد. دلیل آن چیست؟
قبل از توضیح این مسئله باید بین دو کلمه ی مهم تفاوت قائل شوید:
مثال از declare کردن متغیر:
var carName;
مثال از مقدار دهی به متغیر:
carName = "Volvo";
مثال از انتساب مقدار همزمان با declare کردن متغیر:
var carName = "Volvo";
حالا می توانیم کد بالا را توضیح دهیم...
اگر در کد بالا تابع myFunction را به صورت زیر بنویسیم چه اتفاقی می افتد؟
function myFunction() { var carName = "Volvo"; }
حالت اصلی آن که در مثال بالا آمده است به این شکل است:
function myFunction() { carName = "Volvo"; }
تنها تفاوت این دو، وجود کلیدواژه ی var است. همانطور که از جلسات اولیه به یاد دارید، کلیدواژه ی var یک متغیر را ایجاد می کند. قانونی که به شما گفتیم به این ترتیب بود : "اگر مقداری خاص را به متغیری نسبت دهید که به صورت صریح declare نشده باشد، به شکل خودکار تبدیل به یک متغیر سراسری (GLOBAL variable) می شود."
بنابراین اگر از دستور var استفاده کنیم و آن را داخلِ خودِ تابع تعریف کنیم، متغیر ما دیگر از نوع Global نخواهد بود.
تمام مرورگر های مدرن و بروز دنیا به شما اجازه می دهند جاوا اسکریپت را در Strict Mode (به معنی "حالت سختگیرانه") اجرا کنید. در قسمت های بعدی در مورد Strict Mode صحبت خواهیم کرد اما فعلا بدانید در این حالت متغیر ها به هیچ عنوان به صورت خودکار تبدیل به Global نمی شوند.
در جاوا اسکریپت scope سراسری یا Global همان شیء window است که البته هنوز به آن نرسیده ایم. شیء window شیء ای است که تمام محتوای window (پنجره ی مرورگر شما) را در اختیار دارد و تمام متغیر های سراسری (global variables) به آن تعلق دارند.
به مثال زیر توجه کنید:
<!DOCTYPE html> <html> <body> <h2>JavaScript Scope</h2> <p>In HTML, global variables defined with <b>var</b>, will become window variables.</p> <p id="demo"></p> <script> var carName = "Volvo"; // code here can use window.carName document.getElementById("demo").innerHTML = "I can display " + window.carName; </script> </body> </html>
اگر به مثال بالا خوب دقت کنید متوجه می شوید به جای دستور:
document.getElementById("demo").innerHTML = "I can display " + carName;
می توانیم از دستور زیر استفاده کنیم:
document.getElementById("demo").innerHTML = "I can display " + window.carName;
چرا؟ به این دلیل که گفتیم تمام متغیر های Global به شیء window تعلق دارند که همان محیط کامل جاوا اسکریپت است.
هشدار: بدون حساب و کتاب، متغیر ها یا توابع Global ایجاد نکنید چرا که این متغیر ها و توابع می توانند متغیر ها یا توابعِ شیء window را overwrite کنند. تنها زمانی از متغیر های سراسری استفاده کنید که کاملا نسبت به شرایط آگاهی داشته باشید.
نکته: پارامتر ها یا آرگومان های توابع نیز تنها از داخل تابع در دسترس هستند.
بحث امروز، یعنی scope، از بحث های بسیار با اهمیت و اساسی در برنامه نویسی است و بسیاری از اشتباهات برنامه نویسان مبتدی به این بحث مربوط می شود. شما با مرور کردن این مطلب می توانید از چنین اشتباهاتی دوری کنید. به هر حال امیدوارم از این قسمت لذت برده باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.