کلمهٔ this
یک تابعِ برچسب میتواند یک بار اسم لیوان را بگوید، بار بعد کالا را گم کند، و بار سوم اسم فنجان را نشان دهد. آکولادها سر جایشان ماندهاند. چیزی که عوض شده، شکلِ صدا زدن است. JavaScript مقدار this را موقع صدا زدن انتخاب میکند، نه موقعی که تابع را تایپ میکنید.
بعد از فراخوانی سادهٔ متد
درس متدها تابع را روی آبجکت گذاشت و با product.tag() اجرا کرد. در آن شکل، this همان آبجکتِ قبل از نقطه بود. همانجا توقف کرد. اینجا تابع سر جایش میماند و صدا زدن عوض میشود: از روی آبجکت برداشته میشود، با call به جای دیگری نشانه میرود، با bind قفل میشود، یا بهصورت پیکان نوشته میشود.
پنج شکل که this را تعیین میکنند
📊 متد، جدا، call، bind، پیکان
| شکل | نمونه | this کجا مینشیند |
|---|---|---|
| متد | product.tag() |
آبجکتِ قبل از نقطه |
| جدا | let show = product.tag; show() |
آن آبجکت نیست (undefined در حالت سختگیرانه) |
| call | product.tag.call(cup) |
آبجکتی که به call میدهید، فقط برای همین اجرا |
| bind | product.tag.bind(product) |
روی همان آبجکت برای صدا زدنهای بعدی قفل است |
| پیکان | () => this.name داخل تابع دیگر |
this تابع بیرونی، نه آبجکتِ قبل از نقطه |
قبل از خواندن this، شکل صدا زدن را نام ببرید. نشستن تابع روی آبجکت، this را منجمد نمیکند. خودِ صدا زدن تصمیم میگیرد. bind تصمیم را برای یک صدای بعدی از پیش میگیرد. پیکان صدا زدن را نادیده میگیرد و به تابعی نگاه میکند که دورش نوشته شده.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
console.log(product.tag());
نقطه هنوز اسم آبجکت را میگوید
product.tag() تابع tag را اجرا میکند و this را روی product میگذارد. کنسول Mug را چاپ میکند. این همان قاعدهٔ درس متدهاست و اینجا فقط برای مقایسه مانده. چهار صدای بعدی عمداً از همین قاعده جدا میشوند.
"use strict";
let product = {
name: "Mug",
tag() {
if (this == null) {
return "missing";
}
return this.name;
}
};
let show = product.tag;
console.log(show());
تابع را که از آبجکت جدا کنید، لیوان با نقطه میرود
show و product.tag یک تابعاند. show() قبل از نقطه آبجکتی ندارد، پس در حالت سختگیرانه this برابر undefined است. نگهبان missing را برمیگرداند. نگهبان را بردارید تا this.name خطا بدهد. این صفحه با حالت سختگیرانه جلو میرود تا نتیجه قابل پیشبینی بماند. اسکریپتِ بدون این حالت میتواند صدای جدا را به آبجکت سراسری نشانه ببرد.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let cup = { name: "Cup" };
console.log(product.tag.call(cup));
call تابع را برای یک آبجکت قرض میگیرد
product.tag.call(cup) هنوز tag لیوان را اجرا میکند، ولی this فقط برای همین اجرا cup است. کنسول Cup را چاپ میکند. product.name همان Mug میماند. call تابع را روی cup کپی نمیکند. apply همین کار را میکند وقتی آرگومانهای اضافه داخل آرایه باشند — این برچسب به آنها نیاز ندارد.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let show = product.tag.bind(product);
console.log(show());
bind آبجکت را برای صدای جدای بعدی نگه میدارد
bind تابع تازهای برمیگرداند. داخل آن، this همان product میماند حتی اگر show() نقطه نداشته باشد. کنسول Mug را چاپ میکند. خودِ tag اصلی دست نمیخورد. وقتی دکمه، تایمر، یا تابع دیگری قرار است متد را بدون آبجکتِ جلویش صدا بزند، از bind استفاده کنید.
"use strict";
let shelf = {
name: "Shelf",
make() {
let product = {
name: "Mug",
tag: () => this.name
};
return product.tag();
}
};
console.log(shelf.make());
پیکان this را از نقطه نمیگیرد
product.tag() شکلِ فراخوانی متد را دارد، ولی tag پیکان است. پیکان this مخصوص خودش ندارد. this را از make میگیرد و make بهصورت shelf.make() اجرا شده، پس this همان shelf است. کنسول Shelf را چاپ میکند، نه Mug. اگر روی product متد معمولی بود، Mug را میدیدید. پیکان در درس قبلی آمده بود؛ این صفحه فقط اثرش را روی this نشان میدهد.
صدا زدن را با کار جور کنید
آبجکت قبل از نقطه نشسته؟ this را همان آبجکت بخوانید. تابع را جدا کردهاید و bind نکردهاید؟ منتظر آن آبجکت نمانید. یک آبجکت دیگر، فقط برای یک اجرا؟ call را به کار ببرید. صدای بعدی بدون نقطه باید هنوز لیوان را ببیند؟ اول bind. پیکان نوشتهاید؟ به تابعِ دوروبر نگاه کنید، نه به آبجکتِ قبل از نقطه. سازنده و کلاس هم this را تنظیم میکنند و برای صفحهٔ بعدیتر ماندهاند. درس بعد JSON است: متنی که داده را توصیف میکند، نه قاعدهٔ تازهای برای this.
برچسب قفلشده را روی صفحه بگذارید
tag را با bind به لیوان قفل کنید، بعد همان تابع تازه را بدون نقطه صدا بزنید. نتیجه را داخل یک پاراگراف بنویسید.
<!DOCTYPE html>
<html>
<head>
<title>this-keyword — page</title>
</head>
<body>
<p id="line">…</p>
<script>
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let show = product.tag.bind(product);
let box = document.getElementById("line");
box.textContent = show();
</script>
</body>
</html>
پاراگراف Mug را نشان میدهد. show() قبل از نقطه آبجکتی ندارد، ولی خط هنوز اسم لیوان را میگوید چون bind مقدار this را قفل کرده. فقط product.name را عوض کنید، صفحه را تازه کنید، و پاراگراف دنبال همان اسم میرود. درس بعد: کار با JSON — متنی که داده را توصیف میکند، نه قانون تازهای برای this.
گامهای تمرین
product.tag()را صدا بزنید وMugرا بخوانید.- تابع را در
showبگذارید،show()را در حالت سختگیرانه صدا بزنید، وmissingرا بخوانید. product.tag.call(cup)را صدا بزنید وCupرا بخوانید.tagرا بهproductقفل کنید، تابع تازه را بدون نقطه صدا بزنید، وMugرا بخوانید.shelf.make()را اجرا کنید وShelfرا بخوانید، نهMug.- در دموی HTML فقط
product.nameرا عوض کنید، تازه کنید، و پاراگراف را بخوانید.
لغزشهای رایج
- خیال کنید چون تابع روی آبجکت نشسته،
thisمنجمد است show()را در حالت سختگیرانه صدا بزنید و هنوز منتظرMugبمانید- فکر کنید
callتابعtagرا رویcupکپی میکند - انتظار داشته باشید
bindخودِtagاصلی را بازنویسی کند، نه اینکه تابع تازه بدهد - پیکان را جای متد بگذارید و منتظر آبجکتِ قبل از نقطه بمانید
- درس بعد را قاعدهٔ دیگری برای
thisحساب کنید — JSON قالب متنی برای داده است
جمعبندی
thisرا شکل صدا زدن انتخاب میکند، نه آکولادهاobject.method()مقدارthisرا روی آبجکتِ قبل از نقطه میگذارد- صدای جدا در حالت سختگیرانه
thisرا به آن آبجکت نشانه نمیبرد callبرای همان یک اجرا،thisرا روی آبجکتی میگذارد که دادهایدbindتابعی برمیگرداند کهthisدر آن قفل مانده- پیکان
thisرا از تابع دوروبرش میگیرد - صدای قفلشده میتواند یک خط از صفحه را پر کند
- بعدی: کار با JSON، متنی که داده را توصیف میکند
🧠 دانش خود را بیازمایید
دانش خود را بیازمایید
خود را با این آزمون تعاملی به چالش بکشید و ببینید موضوع را چقدر خوب درک کردهاید
📝 دستورالعملها
- هر سوال را با دقت بخوانید
- بهترین پاسخ را برای هر سوال انتخاب کنید
- میتوانید آزمون را هر چند بار که میخواهید تکرار کنید
- پیشرفت شما در بالا نمایش داده میشود