هر 4 Scope جاوااسکریپت به زبانی ساده!
زمان مطالعه:8 دقیقه

هر 4 Scope جاوااسکریپت به زبانی ساده!

اگر حتی یک خط کد جاوا اسکریپت نوشته اید، بدون اینکه متوجه شوید از یکی از چهار scope جاوا اسکریپت استفاده کرده اید و این سطوح مختلف scope در جاوااسکریپت شکل کار کد شما و اینکه کدام متغیر در کجای برنامه قابل دسترس هست را تعیین میکنه و برای اینکه تسلط بهتری روی کد داشته باشیم و کدی پایدار و بدون باگ داشته باشیم لازمه که هر 4 سطح مختلف scope در جاوااسکریپت را بشناسیم  و ما در این مقاله به زبانی ساده هر 4 سطح مختلف scope در جاوااسکریپت یعنی Global Scope, Module Scope, Block Scope, Function Scope را توضیح دادیم.

تعریف Scope

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

const outer = "بیرون"

function test() {
  const inner = "داخل"
  console.log(outer, inner)
  // Print: "Out", "In"
}

test()

console.log(outer, inner)
// Throws Uncaught Reference Error: inner is not defined

در مثال بالا ما 2 متغیر با نام های outer و inner تعریف کردیم، یکی بیرون فانکشن و یکی هم درون فانکشن و سپس از هر دوتای اونها console.log گرفتیم. console.log اول که درون فانکشن نوشته شده بدون مشکل اجرا شد و خروجی مدنظر را به ما داد اما console.log دومی ارور ایجاد کرد و دلیل این ارور هم عدم دسترسی ما به متغیری هست که داخل فانکشن نوشته شده.

در مثال بالا به دوتا از scope های مختلف در جاوااسکریپت اشاره کردیم و دیدیم که این scope ها چطور تعامل کد با متغیرها و بخش های مختلف برنامه را تعیین میکنند. حالا بیایید بریم سراغ هر 4 scope مختلف در جاوااسکریپت و اونهارو یک به یک شرح بدیم.

سطوح مختلف scope در جاوااسکریپت

4 سطح scope در جاوااسکریپت به شرح زیر هستند:

  1. Global Scope
  2. Module Scope
  3. Block Scope
  4. Function Scope

شاید در نگاه اول کمی گیج کننده بنظر برسه و فکر کنید که به خاطر سپردن جزئیات تک تک این scope ها کار دشواریه اما در واقعیت و تقریبا در 80% از کدهایی که مینویسیم صرفا داریم از Module Scope و Block Scope استفاده میکنیم و ما فارغ از این قضیه هر 4 سطح مختلف scope هارا به زبانی ساده و با چند مثال ملموس برای شما شرح میدیم.

Global Scope

بیایید با ساده ترین سطح scope شروع کنیم، سطحی که کمترین میزان محدودیت را داره و خصوصا اگر ابتدای راه مسیر یادگیری جاوااسکریپت هستید اونرو بیشتر دیدید.

برای درک بهتر global scope تصور کنید که یک فایل HTML و یک فایل Javascript همانند مثال زیر داریم:

<script src="script.js"></script>
// script.js

const a = 1
console.log(a)
// خروجی: 1

در مثال بالا ما داریم یک متغیر را در سطح global scope ایجاد میکنیم و هر زمانی که متغیری در بالاترین سطح یک فایل ( خارج از هرگونه فانکشن و { } ) ایجاد بشه، اون متغیر به عنوان یک متغیر global scope در نظر گرفته میشه و در نتیجه در تمامی بخش های برنامه ما قابل دسترس هست!

دسترسی global به یکسری از متغیرها کدنویسی را سریعتر و کار مارو هم در قدم اول راحت تر میکنه چراکه دیگه نیازی نیست نگران عدم دسترسی به یک متغیر در جایی که به اون نیاز داریم داشته باشیم. اما این قضیه به همینجا ختم نمیشه و کمی که کد ما پیچیده تر بشه و تعداد فایل های ما بیشتر بشه مدیریت این قضیه هم سخت تر میشه. به مثال زیر توجه کنید:

<script src="script-1.js"></script>
<script src="script-2.js"></script>
// script-1.js

const a = 1
// script-2.js

console.log(a)
// Prints: 1

همینطور که میبیند متغیری که در فایل script-1.js نوشتیم در فایل script-2.js هم در دسترسه و global scope بودن اون متغیر کاری کرده تا در تمامی بخش های برنامه بتونیم بهش دسترسی داشته باشیم. از اینرو توصیه میکنیم تا جای ممکن از global scope استفاده نکنید چراکه کار نگهداری از کد را دشوار تر میکنه و در بهینه بودن برنامه ما هم تاثیرگذار هست.

Module Scope

module scope شباهت خیلی زیادی به global scope داره که با یک تفاوت اساسی از global scope متمایز میشه. متغیرهای module scope فقط در همان فایلی که تعریف شدن در دسترس هستند و این بدان معناست که ما نمیتونیم از متغیری که در فایل دیگری ایجاد شده استفاده کنیم و این هم به مدیریت آسان تر کد کمک میکنه و هم به بهینه تر بودن برنامه.

جهت module scope شدن فایل نیازه تا type="module" را به تگ script اضافه کنیم:

<script src="script-1.js" type="module"></script>
<script src="script-2.js" type="module"></script>
// script-1.js

const a = 1
console.log(a)
// Prints: 1
// script-2.js

console.log(a)
// Throws Uncaught Reference Error: a is not defined

با همین تغییر جزئی دیگه متغیرهای ما بصورت global و در همه فایل ها در دسترس نیستند و با بزرگتر شدن پروژه با مشکلاتی مثل بهینه نبودن برنامه و یا تداخل دو متغیر مشابه بر نخواهیم خورد.

Block Scope

block scope ساده ترین و قابل فهم ترین scope هست چراکه این scope را با علامت { } ( curly braces ) میشناسیم و scope متغیرهایی که داخل { } محصور شدن دقیقا همین بلوک از کد در نظر گرفته میشه و این بدان معناست که functions, if statements, for loops و .... block scope خودشان را ایجاد میکنند.

function test() {
  const funcVar = "Func"

  if (true) {
    const ifVar = "If"
    console.log(funcVar, ifVar)
    // خروجی: "Func", "If"
  }

  console.log(funcVar, ifVar)
  // Throws Uncaught Reference Error: ifVar is not defined
}

در مثال بالا دو block scope وجود داره و هر block scope فقط به متغیرهایی درون خودش یعنی تمام کدی که داخل { } های خودش نوشته شدن دسترسی داره و این دسترسی به همینجا محدود میشه و ما به کدی که خارج از این { } و داخل یک { } نوشته شده دسترسی نداریم.

البته این استثنا را به خاطر داشته باشید که قضیه برای block scope والد فرق میکنه، یعنی چی ؟ یعنی اینکه در مثال بالا ما یک فانکشن با نام test داریم که یک block scope را ایجاد کرده و ما در بالاترین سطح این فانکشن یک متغیر با نام funcVar ایجاد کردیم و سپس یک block scope جدید در داخل block scope فانکشن test ایجاد کردیم، از اینرو فانکشن test به عنوان والد در نظر گرفته میشه و ما داخل block scope فرزند که if ما باشه به متغیر funcVar دسترسی داریم ولی خارج از if به متغیری که داخل if نوشته شده دسترسی نداریم.

Function Scope

scope آخر ما Function Scope هست و این scope با متغیرهای ایجاد شده با کلمه var در ارتباط هست. متغیرهای var در جاوااسکریپت مرتبط هستند با scope فانکشن ما و این به آن معناست که فقط به { } فانکشن اهمیت میدن.

function test() {
  var funcVar = "Func"

  if (true) {
    var ifVar = "If"
    console.log(funcVar, ifVar)
    // خروجی: "Func", "If"
  }

  console.log(funcVar, ifVar)
  // خروجی: "Func", "If"
}

مثال قبل دقیقا مشابه مثالی هست که در بخش block scope زدیم، با این تفاوت که اینجا متغیر ifVar را به جای استفاده از کلمه const با کلمه var در تعریف کردیم و همینطور که میبینید اینبار کد ما بر خلاف مثال قبلی بدون هیچگونه اروری کار کرد و این بخاطر این هست که کلمه var سطح block را نادیده میگیره و با وجود اینکه متغیر ifVar داخل block شرط ما نوشته شده کار میکنه.

قبلتر در مقاله ایی با عنوان متغیرها در جاوااسکریپت توضیح جامع و کاملی درمورد متغیرها دادیم و همچنین در ادامه در مقالاتی مجزا به شرح اختصاصی ایجاد متغیر با کلمه let و var و const پرداختیم و لپ کلام یک نکته ایی که در این مقالات بهش اشاره شد این بود که تا جای ممکن متغیرهای خودرا با const یا let ایجاد کنید و از ایجاد متغیر با کلمه var بپرهیزید.

متغیرهای مختلف با نام یکسان

یک نکته خیلی مهم درباره Function scope ها داشتن دو متغیر با نام های یکسان داخل یک فانکشن هست.

function test() {
  const a = "Func"

  if (true) {
    const a = "If"
    console.log(a)
    // Prints: "If"
  }

  console.log(a)
  // Prints: "Func"
}

در مثال بالا ما یک متغیر با نام a داریم که در بالاترین سطح فانکشن test نوشته شده و یک متغیر دیگه با همان نام a داریم که داخل بلوک if نوشته شده. وقتی داخل بلوک if از متغیر a لاگ میگیریم با مقدار متغیر a که داخل همان بلوک if نوشته شده مواجه میشیم و وقتیم که خارج از بلوک if از a لاگ میگیریم با مقدار متغیری که در بالاترین سطح فانکشن test ایجاد شده مواجه میشیم.

نتیجه ایی که از کد بالا میگیریم این هست که این 2 متغیر هیچ تداخلی باهم ندارن و به عنوان 2 متغیر مختلف باهاشون رفتار میشه و تنها شباهتشون اسم اونهاست و وقتی سعی میکنیم ازشون استفاده کنیم، نزدیکترین اونها در دسترس ما هستند.

کد بالا کار درست و اصولی نیست چراکه هم نامگذاری های یکسان با اصول کدنویسی تمیز سازگار نیست و هم ما عملا نمیتونیم از متغیر a که در بالاترین سطح فانکشن test نوشته شده استفاده کنیم.

 

scopes

#

variables

#

https://vaspar.io/blog/javascript-scopes

اشتراک گذاری:

نظرات

500

/

0