Closure زمانی رخ میدهد که یک تابع، متغیرهایی از دامنهٔ بیرونی خود را به خاطر میسپارد و حتی در زمانی که در دامنهای دیگر اجرا میشود، همچنان به آنها دسترسی دارد.
فقط توابع دارای closure هستند — نه اشیاء. برای مشاهدهٔ closure، باید تابع را در دامنهای متفاوت از محل تعریفش اجرا کنیم.
function greeting(msg) {
return function who(name) {
console.log(`${msg}, ${name}!`);
};
}
var hello = greeting("Hello");
var howdy = greeting("Howdy");
hello("Kyle"); // Hello, Kyle!
hello("Sarah"); // Hello, Sarah!
howdy("Grant"); // Howdy, Grant!تابع داخلی who به متغیر msg از دامنهٔ بیرونی دسترسی دارد. این دسترسی حتی پس از پایان اجرای greeting حفظ میشود.
function counter(step = 1) {
var count = 0;
return function increaseCount() {
count = count + step;
return count;
};
}
var incBy1 = counter(1);
var incBy3 = counter(3);
incBy1(); // 1
incBy1(); // 2
incBy3(); // 3
incBy3(); // 6تابع increaseCount به متغیرهای count و step دسترسی دارد و مقدار آنها را حفظ و تغییر میدهد.
function getSomeData(url) {
ajax(url, function onResponse(resp) {
console.log(`Response (from ${url}): ${resp}`);
});
}تابع onResponse به url دسترسی دارد، حتی پس از پایان اجرای getSomeData.
for (let [idx, btn] of buttons.entries()) {
btn.addEventListener("click", function onClick() {
console.log(`Clicked on button (${idx})!`);
});
}هر تابع onClick به متغیر idx مربوط به همان تکرار دسترسی دارد.
this یکی از مفاهیم قدرتمند و در عین حال گیجکننده در JS است. برخلاف تصور رایج، this به تابع یا شیء خاصی اشاره ندارد، بلکه به زمینهٔ اجرایی در لحظهٔ فراخوانی تابع وابسته است.
function classroom(teacher) {
return function study() {
console.log(`${teacher} says to study ${this.topic}`);
};
}
var assignment = classroom("Kyle");
assignment(); // Kyle says to study undefinedدر اینجا، چون تابع بدون زمینهٔ اجرایی فراخوانی شده، this.topic برابر undefined است.
var homework = {
topic: "JS",
assignment: assignment
};
homework.assignment(); // Kyle says to study JSتابع بهعنوان متد شیء homework فراخوانی شده و this به آن شیء اشاره دارد.
var otherHomework = {
topic: "Math"
};
assignment.call(otherHomework); // Kyle says to study Mathبا استفاده از call میتوان this را به شیء دلخواه نسبت داد.
Closure به توابع اجازه میدهد متغیرهای بیرونی را حفظ و استفاده کنند، حتی پس از پایان دامنهٔ اصلی. this به زمینهٔ اجرایی وابسته است و در لحظهٔ فراخوانی تعیین میشود. شناخت دقیق این دو مفهوم، پایهای ضروری برای نوشتن کدهای حرفهای در جاوااسکریپت است.