Scope در جاوا اسکریپت چیست؟ – توضیح به زبان ساده + مثال و کد
Scope در جاوا اسکریپت مفهومی اساسی است که دسترسی یا قابل مشاهده بودن متغیرها، اشیا و توابع را تعیین میکند. در واقع به وسیله Scope در JavaScript میتوان محدودهای از کدها را تعیین کرد که در آن به متغیر یا تابع دسترسی داریم. ۲ نوع اصلی Scope در زبان برنامه نویسی جاوا اسکریپت وجود دارند که هر کدام از آنها کاربردهای خاص خودشان را دارند. در این مطلب از «مجله فرادرس»، بحث Scope در جاوا اسکریپت و انواع آن به همراه مثالهایی با زبان ساده آموزش داده خواهد شد.
Scope در جاوا اسکریپت چیست؟
در محیط جاوا اسکریپت، «Scope» به معنای دامنه (محدوده) کدهای کاربر است. این دامنه به عنوان نوعی تعیین کننده دسترسی به توابع و متغیرها در جاوا اسکریپت عمل میکند. به عبارت سادهتر، تصمیم کاربر در مورد مکان اعلان تابع یا متغیر در جاوا اسکریپت، متعاقباً بر دسترسی آن تأثیر میگذارد. از این رو، وقتی متغیری در تابعی اعلان میشود، تنها در محدوده آن تابع قابل دسترسی است.
- نکته: منظور از کلمات «محدوده» و «دامنه» در این بحث یکسان است. همچنین کلمات «محدوده سراسری» و «محدوده جهانی» نیز مترادف هستند.
انواع Scope در جاوا اسکریپت
اصطلاح Scope در جاوا اسکریپت به معنای دسترسی به متغیرها و توابع در بخشهای خاصی از کدها است. در دنیای برنامه نویسی جاوا اسکریپت، محدوده متغیرها به چند دسته زیر تقسیم میشود:
- «محدوده سراسری» (Global Scope)
- «اسکوپ محلی» (Local Scope)
- «محدوده تابع» (Function Scope)
- «اسکوپ بلوک» (Block Scope)
- «محدوده واژگانی» (Lexical Scope)
در ادامه این آموزش Scope در جاوا اسکریپت، تمامی محدودههای نام برده به همراه مثال آموزش داده خواهند شد.
محدوده سراسری در جاوا اسکریپت چیست؟
متغیرهایی که در ابتدای برنامه اعلان میشوند یا آنهایی که در تابعی محصور نشدهاند، در «محدوده سراسری | جهانی» (Global Scope) قرار میگیرند. اصطلاح Scope در جاوا اسکریپت نشان میدهد که آیا متغیر یا تابع میتواند از قسمتهای مختلف کدها قابل دسترسی باشد یا خیر.
محدوده پیشفرض برای متغیرها و توابع در جاوا اسکریپت، محدوده سراسری است. برای نشان دادن این موضوع، توجه به مثال زیر اهمیت زیادی دارد.
1var companion = 'dog';
2function displayCompanion() {
3 console.log(companion); // outputs 'dog' in the console
4}
در قطعه کد داده شده، متغیری به نام companion تعریف شده است. همچنین مقدار dog به این متغیر اختصاص دارد. همچنین تابعی به نام displayCompanion اعلان شده که مقدار companion را در کنسول ثبت میکند. از آنجایی که companion نوعی متغیر سراسری است، میتوان در تابع displayCompanion به آن دسترسی ایجاد کرد. به طور مشابه، میتوان به companion در خارج از تابع دسترسی داشت که خروجی آن به صورت زیر خواهد بود.
1console.log(companion); // outputs 'dog' in the console
با این حال، اگر کاربر سعی داشته باشد به متغیری دسترسی پیدا کند که در محدوده جهانی تعریف نشده است، با خطا مواجه خواهد شد.
1var companion = 'cat';
2function displayCompanion() {
3 console.log(companion); // outputs 'cat' in the console
4}
5console.log(otherCompanion); // outputs 'undefined' in the console
در کدهای بالا، متغیری به نام companion وجود دارد که مقدار cat به آن اختصاص داده شده است و تابعی به نام displayCompanion وجود دارد که companion را ثبت میکند. با این حال، otherCompanion در محدوده جهانی تعریف نشده و بنابراین دسترسی آن خارج از تابع displayCompanion تعریف نشده خواهد بود.
1console.log(otherCompanion); // outputs 'undefined' in the console
چند مثال از Global Scope در جاوا اسکریپت
در جاوا اسکریپت، زمانی که متغیری در ابتدای «اسکریپت» (Script) یا خارج از هر تابعی اعلان میشود، به عنوان متغیر سراسری در نظر گرفته خواهد شد، به این معنی که میتوان به آن دسترسی داشت و در هر جایی از برنامه از آن استفاده کرد.
در ادامه این مطلب از مجله فرادرس چند مثال دیگر برای این نوع محدوده در جاوا اسکریپت آورده شده که مثال اول به صورت زیر است:
1// Script to print a message
2let greeting = "hello";
3
4function sayHello () {
5 console.log(greeting);
6}
7
8sayHello(); // Outputs: hello
در اسکریپت بالا، greeting همانطور که در سطح بالای برنامه اعلان شده، نوعی متغییر سراسری محسوب میشود و حتی در تابع sayHello قابل دسترسی خواهد بود. توجه به این نکته مهم است که مقدار متغیر سراسری را میتوان در تابع تغییر داد. مثال زیر این موضوع را بیان میکند.
1// Script to demonstrate change in global variable
2let greeting = "hello";
3
4function changeGreeting() {
5 greeting = 3;
6}
7
8// before invoking the function
9console.log(greeting);
10
11// after invoking the function
12changeGreeting();
13console.log(greeting); // Outputs: 3
در کدهای بالا، greeting نوعی متغیر سراسری به حساب میآید که به صورت hello مقداردهی شده است. با این حال، در تابع changeGreeting ، مقدار آن به 3 تغییر میکند و این تغییر زمانی که greeting پس از آن ثبت میشود، منعکس خواهد شد.
نکته حائز اهمیت در اینجا این است که تکیه بر متغیرهای سراسری باید به حداقل برسد، زیرا مقادیر آنها را میتوان در مکانهای مختلف در برنامه تغییر داد که این کار به طور بالقوه منجر به بروز نتایج غیرقابل پیشبینی میشود. جالب اینجاست که در جاوا اسکریپت، متغیر را میتوان بدون اعلان صریح در ابتدا باز هم استفاده کرد. اگر این اتفاق بیفتد، متغیر به طور خودکار دامنه سراسری پیدا میکند. مثال زیر برای بیان این موضوع ارائه شده است.
1function sayHello() {
2 greeting = "hello"
3}
4
5sayHello();
6
7console.log(greeting); // Outputs: hello
در این مورد، greeting نوعی متغیر جهانی محسوب میشود، حتی اگر به صراحت اعلان نشده باشد. اگر متغیر با let greeting = "hello" اعلان شود، برنامه خطا ایجاد میکند. باید به این نکته توجه داشت که جاوا اسکریپت نوعی «حالت سخت گیرانه» (Strict Mode) ارائه میدهد که در آن متغیر نمیتواند بدون اعلان اولیه استفاده شود.
محدوده محلی در جاوا اسکریپت چیست ؟
مفهوم «محدوده یا دامنه محلی» (Local Scope) به متغیر یا تابعی اشاره دارد که فقط در بلوک کد فعلی آن قابل دسترسی است.
میتوان با استفاده از {} محدوده محلی ایجاد کرد که مثال زیر این مفهوم را بیان میکند:
1{
2 var companion = 'cat';
3}
4console.log(companion); // outputs 'undefined' in the console
در قطعه بالا، companion مقدار cat را با محدوده محلی ایجاد شده به وسیله {} اختصاص داده است. با این حال، خارج از {} نمیتوان به companion دسترسی پیدا کرد، اما در همان محدوده، قابل دسترسی خواهد بود.
1console.log(companion); // outputs 'cat' in the console
مثالی برای Scope محلی در جاوا اسکریپت
در این بخش مثالی برای Scope در جاوا اسکریپت از نوع محلی ارائه میشود. همانطور که گفته شد، متغیر میتواند دارای محدوده محلی باشد، به این معنی که دسترسی به آن فقط به تابعی خاص محدود میشود. مثال زیر برای درک بهتر این مسئله آورده شده است.
1// Demonstrating the local scope of a variable
2let a = "hello";
3
4function greet() {
5let b = "World"
6console.log(a + b);
7}
8
9greet();
10console.log(a + b); // error
11Execute Code
12//Output
13
14//helloWorld
15//Uncaught ReferenceError: b is not defined
در قطعه کد بالا، متغیر a نوعی متغیر سراسری در نظر گرفته میشود، در حالی که متغیر b متغیری محلی است. دسترسی به متغیر b به تابع greet محدود شده است. در نتیجه، زمانی که تلاشی برای دسترسی به متغیر b خارج از تابع آن انجام میشود، خطایی ایجاد خواهد شد.
- نکته: همانطور که در تصویر بالا معلوم است، محدوده محلی، خود میتواند شامل ۳ نوع محدوه تابع، محدوه بلوک و محدوده «ماژول» (Module) باشد.
محدوه تابع در جاوا اسکریپت چیست؟
یکی دیگر از انواع Scope در جاوا اسکریپت، «محدوده تابع» (Function Scope) است که محدوده محلی را با تفاوتی کوچک منعکس میکند. در این نوع محدوده، متغیرها و توابعِ تعریف شده در داخل تابع را نمیتوان به صورت سراسری در دسترس قرار داد.
مثال زیر برای درک این نوع محدوده در جاوا اسکریپت مهم است.
1function displayCompanion() {
2 var companion = 'cat';
3 console.log(companion); // outputs 'cat' in the console
4}
در مثال فوق، companion در displayCompanion تعریف شده است، از این رو فقط در داخل تابع قابل دسترسی خواهد بود و خارج از تابع، غیر قابل دسترسی است.
1console.log(companion); // outputs 'undefined' in the console
محدوده بلوک در جاوا اسکریپت
نوعی دیگری از Scope در جاوا اسکریپت، نوع بلوکی آن یا «محدوده بلوکی» (Block Scope) است. محدوده بلوک کاربر را قادر میسازد تا متغیرها و توابع را منحصراً برای بلوک کد خاصی (هر بخش محصور در {} ) تعریف کند.
میتوان با استفاده از کلمات کلیدی let یا const محدوده بلوکی ایجاد کرد. مثال زیر برای درک این مفهوم ضروری است.
1let companion = 'cat';
2if (true) {
3 let companion = 'dog';
4 console.log(companion); // outputs 'dog' in the console
5}
6console.log(companion); // outputs 'cat' in the console
در قطعه بالا، از let برای تعریف companion در عبارت if استفاده شده و نوعی محدوده بلوک ایجاد شده است. خارج از بلوک کد سراسری، companion غیر قابل دسترسی باقی میماند:
1console.log(companion); // outputs 'undefined' in the console
- نکته: برای متغیرهای Block Scope در جاوا اسکریپت، محدودهای ایجاد نمیشود.
مثال Block Scope در جاوا اسکریپت
همانطور که بیان شد، کلمه کلیدی let در جاوا اسکریپت نوعی متغیر با محدوده بلوکی تعریف میکند، به این معنی که متغیر فقط در بلوکی که در آن اعلان شده، قابل دسترسی است.
مثال زیر برای نشان دادن مفهوم محدوده بلوکی برای درک بهتر این موضوع اهمیت زیادی دارد.
1// A program demonstrating the block scope notion
2// Global variable
3let a = 'Hello';
4
5function greet() {
6
7javascript
8Copy code
9// Local variable
10let b = 'World';
11
12console.log(a + ' ' + b);
13
14if (b == 'World') {
15
16 // Block-scoped variable
17 let c = 'hello';
18
19 console.log(a + ' ' + b + ' ' + c);
20}
21
22// Variable c isn't accessible here
23console.log(a + ' ' + b + ' ' + c);
24}
25
26greet();
خروجی کدهای بالا به صورت زیر است:
Hello World Hello World hello Uncaught ReferenceError: c is not definedتشریح کد بالا به صورت زیر است:
- a متغیری سراسری بوده و در هر جایی از برنامه قابل دسترسی است.
- b متغیری محلی بوده که فقط در داخل تابع greet قابل دسترسی است.
- c متغیری با محدوده بلوک بوده که فقط در بلوک دستور if قابل دسترسی است.
در برنامه فوق، ۲ اجرای اول console.log() بدون مشکل اجرا میشوند. با این حال، در سومین فراخوانی console.log() سعی میشود به متغیر c با محدوده بلوک در خارج از بلوک آن دسترسی پیدا شود که منجر به خطا خواهد شد.
توجه به این نکته مهم است که در جاوا اسکریپت، در حالی که var دارای محدوده تابعی است، let محدوده بلوکی دارد. اگر let c = 'hello' با var c = 'hello' در عبارت if جایگزین شود، در نتیجه برنامه با موفقیت اجرا خواهد شد. زیرا c به عنوان نوعی متغیر محلی در نظر گرفته میشود.
محدوده واژگانی در جاوا اسکریپت
یکی دیگر از انواع Scope در جاوا اسکریپت، «محدوده واژگانی» (Lexical Scope) است. محدوده یا دامنه واژگانی، که همچنین به عنوان «محدوده ایستا» (Static Scope) یا «محدوده کامپایل-زمان» (Compile-Time Scope) نیز شناخته میشود، مفهوم پیچیدهتری است.
این محدوده به وسیله مکان متغیری در کد تعیین میشود، به این معنی که متغیرها در محدوده مشابه متغیرهای والد قابل دسترسی هستند. مثال زیر این مفهوم را بیان میکند.
1var companion = 'cat';
2function displayCompanion() {
3 console.log(companion); // outputs 'cat' in the console
4}
در مثال فوق، companion در محدوده سراسری تعریف شده و در displayCompanion قابل دسترسی است. اما در بلوک کد، companion قابل دسترسی نیست:
1if (true) {
2 var companion = 'dog';
3 console.log(companion); // outputs 'dog' in the console
4}
5console.log(companion); // outputs 'undefined' in the console
در قطعه کد فوق، companion با استفاده از "var در داخل عبارت if تعریف شده و خارج از بلوک کد غیر قابل دسترسی است:
1console.log(companion); // outputs 'undefined' in the console
سخن پایانی
مفهوم scope در جاوا اسکریپت بحثی اساسی به حساب میآید که دسترسی به متغیرها و توابع را دیکته میکند. قوانین scope به طور یکنواخت برای متغیرهای const و let اعمال میشود، خواه آنها در بلوکی از کدها، تابع یا ماژولی خاص قرار بگیرند. در مقابل، متغیرهای var تنها زمانی از این قوانین پیروی میکنند که در تابع یا ماژولی قرار گیرند.
استفاده مناسب از Scope در جاوا اسکریپت مزایای مختلفی از جمله افزایش امنیت و پتانسیل استفاده مجدد از کدها را ارائه میدهد. در این مطلب از مجله فرادرس بحث Scope در Javascript به صورت نسبتاً کامل بحث شد و انواع این Scopeها به همراه مثالهایی با زبان ساده بحث شدند.