درک closure های جاوا اسکریپت: رویکرد عملی

درک closure های جاوا اسکریپت: رویکرد عملی
یادگیری یک زبان جدید شامل یک سری از مراحل است،  درحالی‌که تسلط برآن زبان، محصول صبر، تمرین، اشتباه و تجربه است.
برخی از توسعه دهندگان دانش کافی برای ارائه ویژگی های درخواست شده توسط مشتری را دارند، اما برای اینکه یک توسعه‌دهنده خوب بود، این کافی نیست.
یک توسعه‌دهنده خوب، کسی است که وقت می‌گذارد تا به عقب بر‌گردد  و مفاهیم پایه زبان را درک کند.
در این مقاله نگاه عمیقی به closure های جاوااسکریپت خواهیم داشت و امیدواریم که این اطلاعات در پروژ‌های شما سودمند باشد.
فروشگاه ساز
فروشگاه اینترنتی و وب سایت خود را به سرعت با سایت ساز سی می پلاس بسازید
تولید ساک تبلیغاتی بگیران
چاپ ساک کاغذی و تبلیغاتی
فروش ویژه مبلمان استیل
خرید انواع مبلمان استیل زیبا با درجه کیفی بالا و ضمانت نامه محصول از تولیدکننده
خودتان را اینجا معرفی کنید

Closure جاوا‌اسکریپت چیست؟

closure جاوا‌اسکریپت زمانی است که یک تابع داخلی به اعضای تابع بیرونی دسترسی پیدا می‌کند (حوزه‌ی لغوی) حتی هنگام اجرای محدوده‌ی خارج از تابع بیرونی. بنابراین نمی‌توانیم بدون توجه به توابع و محدوده، در مورد closure‌ها صحبت کنیم .

Scope در جاوا‌اسکریپت

محدوده به میزان دید متغیر تعریف شده در یک برنامه اشاره دارد. راه‌هایی که برای ایجاد محدوده در جاوااسکریپت وجود دارند عبارتند از: بلوک های try-catch، توابع و کلمه کلیدی let. عمدتا دو نوع محدوده وجود دارد: محدوده جهانی (global scope) و محدوده محلی (local scope).

 

var initialBalance = 0 // Global Scope

function deposit (amount) {
  /**
   * Local Scope
   * Code here has access to anything declared in the global scope
   */
  var newBalance = parseInt(initialBalance) + parseInt(amount)
  return newBalance
}

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


var initialBalance = 300 // Variable declared in the Global Scope

function withdraw (amount) {
  var balance // Variable declared in function scope

  balance = parseInt(initialBalance) - parseInt(amount)
  return balance
}
console.log(initialBalance) // Will output initialBalance value as it is declared in the global scope
console.log(balance) // ReferenceError: Can't find variable: balance

Lexical Scope

محدوده لغوی جاوااسکریپت در مرحله‌ی کامپایل تعیین می‌شود. دامنه لغوی، محدوده یک متغیر را طوری تنظیم می‌کند که تنها در داخل بلوک کدی که در آن تعریف شده‌است، قابل فراخوانی و ارجاع باشد.
تابعی که در داخل یک بلاک تابع احاطه‌کننده تعریف می‌شود، به متغیر‌ها، در محدوده‌ی لغوی تابع احاطه کننده، می‌تواند دسترسی داشته‌باشد.
فراخوانی یک تابع داخلی، خارج از تابع محصور آن و در عین حال حفظ دسترسی به متغیر‌های تابع محصور آن (محدوده لغوی)، یک closure جاوا‌اسکریپت ایجاد ‌می‌کند.
 


var initialBalance = 300 // Global Scope

function withdraw (amount) {
  /**
   * Local Scope
   * Code here has access to anything declared in the global scope
   */
  var balance = parseInt(initialBalance) - parseInt(amount)

  const actualBalance = (function () {
    const TRANSACTIONCOST = 35
    return balance - TRANSACTIONCOST /**
     * Accesses balance variable from the lexical scope
     */
  })() // Immediately Invoked Function expression. IIFE

  // console.log(TRANSACTIONCOST) // ReferenceError: Can't find variable: TRANSACTIONCOST
  return actualBalance
}

یک closure به ما اجازه می‌دهد یک رابط عمومی را در معرض نمایش قرار دهیم در حالی‌که در همان زمان محتویات اجرا را از محدوده خارجی پنهان می‌کنیم.
برخی از الگوهای طراحی جاوا اسکریپت از closure استفاده می کنند.

Module Pattern

یکی از این الگو‌ها که به خوبی پیاده‌سازی شده، الگوی ماژول است. این الگو اجازه می‌دهد تا اعضای خصوصی(private)، عمومی(public) و ممتاز(privileged) را شبیه‌سازی کنید.
 


var Module = (function () {
  var foo = 'foo' // Private Property

  function addToFoo (bam) { // Private Method
    foo = bam
    return foo
  }

  var publicInterface = {
    bar: function () { // Public Method
      return 'bar'
    },
    bam: function () { // Public Method
      return addToFoo('bam') // Invoking the private method
    }
  }

  return publicInterface // Object will contain public methods
})()

Module.bar() // bar
Module.bam() // bam

در الگوی ماژول فوق، تنها متد‌های عمومی و ویژگی‌هایی که در return object وجود دارند، در خارج از محیط اجرای closure،  قابل دسترسی خواهند بود.
تمام اعضای خصوصی همچنان وجود دارند زیرا محتوای اجرایی آن‌ها حفظ می‌شود اما از دید محدوده خارجی، پنهان هستند.
زمانی که یک تابع را در setTimeout یا هر تابع فراخوانی کننده دیگر، قرار می‌دهیم، این تابع همچنان محدوده لغوی را به خاطر closure به یاد خواهد داشت.
 


function foo () {
  var bar = 'bar'
  setTimeout(function () {
    console.log(bar)
  }, 1000)
}

foo() // bar

Closure  و حلقه‌ها
 


for (var i = 1; i <= 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i)
}
/**
* Prints 1 thorugh 5 after each second
* Closure enables us to remember the variable i
* An IIFE to pass in a new value of the variable i for each iteration
* IIFE (Immediately Invoked Function expression)
*/

for (let i = 1; i <= 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i)
}
/**
* Prints 1 through 5 after each second
* Closure enabling us to remember the variable i
* The let keyword rebinds the value of i for each iteration
*/


منبع: scotch.io

فرناز عبداللهی هستم دانشجوی مهندسی فناوری اطلاعات، با شروع از html , css وارد حوزه ی طراحی وب شده ام و در حال حاضر در حال یادگیری جاوا اسکریپت می باشم.

نظرات و سوالات کاربران

هنوز دیدگاه و یا سوالی ارسال نشده است.
هم اکنون شما اولین دیدگاه را ارسال کنید.