this، call، apply، bind
this یعنی «شیئی که الان تابع روش صدا زده شده». مقدارش موقع فراخوانی تعیین میشه (بهجز arrow function).
this یعنی «شیئی که الان تابع روش صدا زده شده». مقدارش موقع فراخوانی تعیین میشه (بهجز arrow function).
قواعد تعیین this
۱. فراخوانی ساده
function show() { return this; }
show(); // حالت عادی: globalThis (window/global)
// در "use strict": undefined
۲. فراخوانی بهعنوان متد
this = آبجکت سمت چپ نقطه:
const user = {
name: "Ali",
hi() { return `سلام ${this.name}`; },
};
user.hi(); // → "سلام Ali"
۳. گم شدن this
const f = user.hi;
f(); // this = undefined/global → "سلام undefined" (یا خطا)
setTimeout(user.hi, 0); // همین مشکل
[1].forEach(user.hi); // همین مشکل
۴. سازنده (new)
function Person(name) {
this.name = name; // this = آبجکت جدید
}
new Person("Sara").name; // → "Sara"
۵. صریح: call/apply/bind
(پایینتر)
۶. Arrow function
this رو از scope بیرونی (lexical) میگیره و هیچوقت عوض نمیشه:
const timer = {
seconds: 0,
start() {
setInterval(() => {
this.seconds++; // this = timer ✅
}, 1000);
},
};
با تابع معمولی داخل setInterval، this درست نبود.
arrow function رو بهعنوان متد object ننویس:
const bad = {
name: "x",
hi: () => this.name, // this = بیرون object (undefined یا global)
};
۷. Event handler (DOM)
button.addEventListener("click", function () {
this; // → خود button
});
button.addEventListener("click", (e) => {
e.currentTarget; // → button (در arrow از این استفاده کن)
});
۸. class
class Btn {
label = "OK";
handle = () => console.log(this.label); // arrow field: this ثابته
other() { console.log(this.label); } // اگه جدا بشه this گم میشه
}
call
فراخوانی فوری با this دلخواه و آرگومانهای جدا:
function intro(greet, punct) {
return `${greet}, ${this.name}${punct}`;
}
const p = { name: "Ali" };
intro.call(p, "سلام", "!"); // → "سلام, Ali!"
apply
مثل call ولی آرگومانها در آرایه:
intro.apply(p, ["سلام", "!"]); // → "سلام, Ali!"
Math.max.apply(null, [1, 5, 3]); // → 5 (امروز: Math.max(...arr))
حافظه: Apply = Array.
bind
تابع جدید با this ثابت برمیگردونه (فوری اجرا نمیکنه):
const boundIntro = intro.bind(p, "سلام");
boundIntro("؟"); // → "سلام, Ali؟"
Partial application
function mul(a, b) { return a * b; }
const double = mul.bind(null, 2);
double(5); // → 10
حل مشکل گم شدن this
const safe = user.hi.bind(user);
setTimeout(safe, 0); // ✅
bindشده را نمیشه دوباره bind کرد (اولی میمونه).bound.name→"bound hi".
قرض گرفتن متد (Method Borrowing)
function sumArgs() {
return Array.prototype.reduce.call(arguments, (a, b) => a + b, 0);
}
sumArgs(1, 2, 3); // → 6
Array.prototype.map.call("abc", (c) => c.toUpperCase()); // → ["A","B","C"]
globalThis و strict mode
"use strict";
function f() { return this; }
f(); // → undefined (نه window)
ماژولهای ES و class ها همیشه strict هستن.
جدول خلاصه
| روش فراخوانی | مقدار this |
|---|---|
fn() | undefined (strict) / global |
obj.fn() | obj |
new Fn() | آبجکت تازهساخته |
fn.call(x) / apply(x) / bind(x) | x |
| arrow function | this بیرونی |
| event handler (تابع معمولی) | عنصر DOM |
تمرین
- بدون اجرا پیشبینی کن خروجی چیه:
const o = {
n: 1,
a() { return this.n; },
b: () => typeof this,
c() { return [1].map(() => this.n); },
};
console.log(o.a(), o.b(), o.c());
// → 1 "object" [ 1 ]
// (در Node با CommonJS. در ماژول ESM مقدار this سطح بالا undefined است و b() مقدار "undefined" برمیگردونه.)
- تابع
myBind(fn, ctx)بنویس که رفتارbindرو پیاده کنه:
const myBind = (fn, ctx, ...pre) => (...args) => fn.apply(ctx, [...pre, ...args]);