Closure و this در جاوااسکریپت – حافظهٔ دامنه و زمینهٔ اجرایی در توابع

Closure و this دو مفهوم بنیادی و گاه گیج‌کننده در جاوااسکریپت هستند. این مقاله به تعریف دقیق closure به‌عنوان حافظهٔ متغیرهای بیرونی در توابع، و بررسی رفتار پویا و وابسته به نحوهٔ فراخوانی در this می‌پردازد. با مثال‌های عملی، تفاوت بین دامنهٔ ثابت و زمینهٔ اجرایی پویا روشن می‌شود.

closurethisexecution-contextscope

~3 دقیقه مطالعه • بروزرسانی ۲۸ مهر ۱۴۰۴

Closure چیست؟


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 حفظ می‌شود.


Closure با داده‌های قابل‌تغییر:


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 دسترسی دارد و مقدار آن‌ها را حفظ و تغییر می‌دهد.


Closure در کدهای ناهم‌زمان:


function getSomeData(url) {
  ajax(url, function onResponse(resp) {
    console.log(`Response (from ${url}): ${resp}`);
  });
}

تابع onResponse به url دسترسی دارد، حتی پس از پایان اجرای getSomeData.


Closure در حلقه‌ها:


for (let [idx, btn] of buttons.entries()) {
  btn.addEventListener("click", function onClick() {
    console.log(`Clicked on button (${idx})!`);
  });
}

هر تابع onClick به متغیر idx مربوط به همان تکرار دسترسی دارد.


this چیست؟


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 به آن شیء اشاره دارد.


فراخوانی با call:


var otherHomework = {
  topic: "Math"
};
assignment.call(otherHomework); // Kyle says to study Math

با استفاده از call می‌توان this را به شیء دلخواه نسبت داد.


جمع‌بندی


Closure به توابع اجازه می‌دهد متغیرهای بیرونی را حفظ و استفاده کنند، حتی پس از پایان دامنهٔ اصلی. this به زمینهٔ اجرایی وابسته است و در لحظهٔ فراخوانی تعیین می‌شود. شناخت دقیق این دو مفهوم، پایه‌ای ضروری برای نوشتن کدهای حرفه‌ای در جاوااسکریپت است.


نوشته و پژوهش شده توسط دکتر شاهین صیامی