در یادگیری یک زبان برنامهنویسی درک مفاهیم اساسی، کمک زیادی به تسریع یادگیری آن زبان میکند. در javascript ، this کلمه کلیدی که یکی از این سنگ بناها است.
این کلمه کلیدی در JavaScript یکی از کلمات کلیدی بسیار مهم است. برخی از مبتدیان با کلمات و برخی دیگر با ماهیت پویای آن دست و پنجه نرم میکنند.
در این مقاله, ما سعی داریم که کلمه کلیدی this را مورد بررسی قرار دهیم و در انجام تمرین مباحث اشکالزدایی(debugging) و نحوه کار با آن به شما کمک کنیم، که در غیر این صورت این موضوع کاملا ً برای شما پیچیده خواهد بود.
کلمه کلیدی this چیست؟
با پشت سرگذاشتن چند مورد کد مفهومی، دو سوال اساسی وجود دارد که باید برای اجرای کد گفته شده به آنها پاسخ دهید:
- کد در کجا اجرا میشود (به عنوان مثال، در یک تابع یا به صورت گلوبال)؟
- دقیقاً کد چیست (به عنوان مثال، یک متد آرایه ای یا یک متد آبجکتی)؟
این کلمه کلیدی به شما کمک میکند تا متوجه شوید که کد کجا تولید شده است، به این خاطر که به آبجکت آن به عنوان متن اجرای(execution context) کد شناخته میشود.
متن اجرا، همسایگی یک قطعه کد را مشخص میکند. متأسفانه، نام نامناسب آن است که منجر به ایجاد سردرگمی در بین توسعه دهندگان جدید JavaScript میشود.
به طور پیش فرض، همه کدها در متن اجرا، به صورت گلوبال راهاندازی میشوند، در مقابل زمینه اجرای محلی مانند تابع body عمل میکند. میتوان این طور فرض کرد که متن اجرای گلوبال را حیاط خود و زمینه اجرای محلی را خانه خود در نظر بگیرید.
دامنه همان چیزی است که قابلیت مشاهده یا دسترسی کد را در متن اجرا تعریف میکند. به عنوان مثال، این که بگوییم متغیرهای cats از دامنه تابع ()catMaker خارج هستند، به این معنی است که تابع ()catMaker به متغیرهای cats دسترسی ندارد، زیرا catsها در زنجیره دامنه ()catMaker نیستند. زنجیره دامنه همه متغیرهایی را که یک متن اجرای خاص میتواند به آنها دسترسی داشته باشد تعریف میکند.
اطلاعات زیادی در مورد این موضوع وجود دارد، اما شما واقعاً باید این را درک کنید تا this را درک کنید. اگر هنوز برای یادگیری این موضوع در تلاش هستید، ناامید نشوید، شما تنها نیستید.
this را کجا پیدا خواهید کرد؟
بیایید مواردی را که با کلمه کلیدی this مواجه میشویم را بررسی کنیم.
متن اجرای گلوبال
متن اجرای گلوبال به صورت پیشفرض است که درون خود متن اجرای محلی را داراست. اگر بخواهید برخی از کدها را بنویسید، متن مربوطه به شرح زیر تعریف میشود.
let myName = "John Doe";
// global execution context
function sayName() {
// local execution context
console.log(myName);
}
در متن اجرای گلوبال، مقدار this همان چیزی است که به عنوان آبجکت window در مرورگر معروف است. آبجکت window را به عنوان یک برگه در نظر بگیرید، زیرا حاوی انواع جزئیات فانتزی مربوط به آن در یک مرورگر میباشد. برای تأیید اینکه this همان آبجکت window در متن اجرای گوبال است، میتوانید قطعه کد زیر را اجرا کنید.
console.log(this === window); // prints true
توابع ساده
توابع متن و دامنه، اجرای خاص خود را دارند، اما اگر تابعی را در متن اجرای گلوبال تعریف کنید، مقدار آن دوباره همان آبجکت window خواهد بود.
function someFunc() {
return this;
}
someFunc() === window; // returns true
ممکن است این موضوع مطلوب باشد یا نباشد. اگر میخواهید از این امر جلوگیری کنید، میتوانید آنچه را که به عنوان حالت strict(دقیق) در javascript شناخته میشود فعال کنید. این به معنای واقعی کلمه javascript را مجبور میکند تا در صورت لزوم خطاهای بیشتری را تولید کند، و در نهایت به کد قابل پیشبینی منجر میشود. وقتی حالت strict فعال باشد، this به کد تعریف نشده منجر میشود.
function someFunc() {
"use strict"
console.log(this);
}
someFunc(); // returns undefined
همچنین ممکن است مواردی وجود داشته باشد که شما بخواهید آنچه را که در this برای یک تابع است به چیز دیگری تغییر دهید، که میتوان گفت کم و بیش متن آن تابع تغییر پیدا کرده است. برای این کار میتوانید از توابع call(), apply() و bind() استفاده کنید. با شروع مورد دوم، تابع bind () تابعی را با مقدار this که ارائه میدهید متصل میکند و یک تابع جدید را برمیگرداند.
const obj = {
message: "hello world"
}
function printMessage() {
console.log(this.message);
};
const boundPrintMessage = printMessage.bind(obj);
printMessage(); // prints undefined
boundPrintMessage(); // prints "hello world"
تابع bind () ابزاری بسیار قدرتمندی است که میتواند به شما در ایجاد کد قابل استفاده مجدد و حل برخی از مشکلات کمک کند، که بعداً به برخی از آنها خواهیم پرداخت.
اگر می خواهید از برگرداندن تابع جدید محدود مقدار this جلوگیری کنید، باید از call() یا apply()استفاده کنید. call() و apply()هر دو به شما اجازه میدهند تابعی را با مقداری که از this ارائه شده فراخوانی كنید، بجز استفاده از call()، میتوانید از طریق apply() پارامترها به صورت آرایه به تابع منتقل كنید.
const user = {
name: 'John Doe'
}
function printUser(likes) {
console.log(`My name is ${this.name}, and I like ${likes}`)
};
printUser.call(user, 'apples')
printUser.apply(user, ['apples'])
توابع Arrow
توابع Arrow (پیکان)، به عنوان توابع Arrow ES6 شناخته می شوند، تقریباً مشابه توابع ساده هستند، البته با چند استثنا مهم. برای اولین بار، برخلاف توابع ساده، مقدار this برای آبجکت window پیش فرض نیست. شما میتوانید توابع Arrow را با فلش در یک آبجکت نشان دهید.
const obj = {
message: "hello world",
arrowFunc: () => console.log(this.message),
plainFunc: function() {
console.log(this.message);
}
}
obj.arrowFunc() // prints undefined
obj.plainFunc() // prints hello world
از آنجا که توابع Arrow ارزش مقدار this خود را در این شرایط ندارند، توصیه نمیشود از توابع Arrow به عنوان متدهای آبجکت استفاده کنید. ممکن است فکر کنید از آنجا که bind() به شما این امکان را میدهد که مقدار this را برای تابع تغییر دهید، میتوانید برای جلوگیری از این رفتار از bind() استفاده کنید، اما این کار اشتباه است.
const obj = {
message: "hello world",
arrowFunc: () => console.log(this.message),
plainFunc: function() {
console.log(this.message);
}
}
const boundArrowFunc = obj.arrowFunc.bind(obj);
boundArrowFunc(); // prints undefined
call () ، ()apply و ()bind برای اجرای توابع در محدودهای که شما تعریف میکنید معرفی شدند، اما مقدار این توابع Arrow به دامنهای که در آن تعریف شده بستگی دارد.
Classها
کلاسهای ES6 همیشه در حالت strict کارمیکنند، بنابراین مقدار this کلاسها با آبجکت window یکسان نیست. همانطور که ممکن است بدانید، کلاسهای ES6 نوعی syntax sugar است، بنابراین اگر بخواهید کلاس ES6 را به سبک توابع سنتی بنویسید، مقدار this آبجکت window خواهد بود.
ارزش this در کلاسها به نحوه فراخوانی آنها بستگی دارد. به همین ترتیب، ممکن است مواردی وجود داشته باشد که بخواهید مقدار this را برای نمونه کلاس تعیین کنید.
class Person {
constructor() {
this.name = "John Doe"
this.sayName = this.sayName.bind(this); // Try running the code without this line
}
sayName() {
console.log(this.name);
}
}
const somePerson = new Person();
somePerson.sayName();
const sayName = somePerson.sayName;
sayName();
اگر با React کار کرده باشید، ممکن است هنگام نوشتن کلاس component ها که با الگو سختگیرانه معروف هستن، آشنا باشید. وقتی مقدار this را در event handlerهای خود به مقدار کلاس متصل نکنید، مقدار this تعریف نمیشود.
چگونه می توان تعیین کرد که this با چه چیزی حل می شود
ما برخی از موارد متداول را مرور کردهایم، اما، موارد دیگری نیز وجود دارد که ممکن است با آنها روبرو شوید. برای کمک به تعیین این که چگونه میتوان این مباحث را حل کرد، به نکات زیر توجه کنید.
- اگر کد داخل بدنه یا بلوک نیست، پس this همان آبجکت window در مرورگر است
- اگر کد به عنوان یک روش آبجکت فراخوانی شده و از طریق نقطه گذاری بیان میشود، پس به سمت چپ نگاه کنید. هرچه در سمت چپ است همان است که this است
- اگر کد درون یک تابع باشد، در صورت فعال نبودن حالت strict، this همان آبجکت window است. وقتی حالت strict فعال است، this همانطور که باید تعریف نمیشود
- اگر تابع یک روش آبجکت باشد، پس یک تابع ساده است، که this به آبجکتی که تابع در آن تعریف شده است منجر میشود، در حالی که یک تابع Arrow به متن اجرای محصور اشاره دارد.
- اگر میخواهید مقدار this برای یک تابع تعیین شود، باید از call(), apply() یا bind() استفاده کنید.
نتیجه
درک اصول اولیه javascript به شما کمک میکند تا با چارچوبهای پیچیده و کتابخانهها درگیر شوید و از آنها تجربه کسب کنید. اگر میخواهید دیباگینگ و نوشتن کد بدون خطا را یاد بگیرید، باید درک کاملی از موضوعاتی مانند کلیدواژه this داشته باشید.
همچنین اگر در زمینه یادگیری با مشکل مواجه شدید نگران نباشید، موضوعات این مجموعه ممکن است مدتی طول بکشد تا به طور کامل آنها را فرا بگیرید. برای رسیدن به یک درک روشن، باید کدنویسی کنید، ازمون وخطا کنید. این به استحکام درک شما و رسیدن به مرحله بعدی کمک خواهد کرد.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید