درک closure های جاوا اسکریپت: رویکرد عملی
برخی از توسعه دهندگان دانش کافی برای ارائه ویژگی های درخواست شده توسط مشتری را دارند، اما برای اینکه یک توسعهدهنده خوب بود، این کافی نیست.
یک توسعهدهنده خوب، کسی است که وقت میگذارد تا به عقب برگردد و مفاهیم پایه زبان را درک کند.
در این مقاله نگاه عمیقی به closure های جاوااسکریپت خواهیم داشت و امیدواریم که این اطلاعات در پروژهای شما سودمند باشد.
دارالترجمه رسمی پارسیس شامل خدمات ترجمه رسمی و تخصصی در بیش از 60 زبان زنده دنیا
بهترین افزونه های سئو وردپرس به صورت کاملا فارسی
فرم ساز آسان اولین فرم ساز کاملا فارسی وردپرس
خرید انواع ورق گالوانیزه رنگی با بهترین قیمت
بهترین کارگاه رویه کوبی و تعمیر مبل راحتی و استیل در تهران با قیمت و کیفیت عالی
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
نظرات و سوالات کاربران
هم اکنون شما اولین دیدگاه را ارسال کنید.