این مقاله در دسته بندی مباحث پیشرفته است, برای فهم آن باید به مباحث پایه مسلط باشید.
ممکن است این مباحث زیاد مهم نباشند چون خیلی از برنامه نویسان باتجربه ای هستند که کارشان به خوبی پیش میرود و این مباحث را نمیدانند. اگر علاقه مند به دانستن اینکه دستورات چگونه کار میکنند هستید بخوانید.
با فراخوانی یک متد به صورت پویا و داینامیک ممکن است مقدار this
از دست برود.
به عنوان مثال:
let user = {
name: "John",
hi() { alert(this.name); },
bye() { alert("Bye"); }
};
user.hi(); // works
// اجرا شود user.by و درغیراینصورت user.hi بود متد john حال بررسی میکنیم اگر نام برابر
(user.name == "John" ? user.hi : user.bye)(); // Error!
در خط آخر ما شرط سه تایی (تک خطی) را داریم که براساس true یا false بودن مقدار user.name
مشخص میشود که آیا متد user.hi
اجرا میشود یا user.bye
. نتیجه true است و user.hi
برگردانده میشود.
ولی چون متد پرانتز ندارد درهنگام اجرا با مشکل روبرو خواهیم بود.
همانطور که میبینید هنگام اجرا به ارور برخورد کردیم. چون مقدار "this"
برابر با undefined
است.
کد زیر کار میکند (آبجکت با عملگر نقطه):
user.hi();
اما این کد اصلا کار نمیکند! (فانکشن بدون پرانتز)
(user.name == "John" ? user.hi : user.bye)(); // Error!
چرا؟ اگر متوجه شدید که تا اینجا چه اتفاقی افتاده, بیایید به عملکرد ()obj.method
بپردازیم.
توضیحات درباره Reference type
نگاه کنید. عبارت ()obj.method
دو عملگر داخل خود دارد:
- ابتدا, عملگر نقطه
'.'
ویژگیobj.method
را پیدا میکند. - سپس پرانتز
()
آن را اجرا میکند.
خب پس چگونه اطلاعات مربوط به this
از قسمت اول به دوم منتقل میشود؟
اگر ما این دستور را در خط های جداگانه ای قرار بدهیم, مطمئنا مقدار this
از دست خواهد رفت:
let user = {
name: "John",
hi() { alert(this.name); }
};
// اگر به این صورت در دو خط جدا متد را صدا بزنیم:
let hi = user.hi;
hi(); // است undefiend برابر با this خطا! چون مقدار
در اینجا hi = user.hi
تابع را در متغیر میریزد و چون خط آخر مستقل و از نظر جاوااسکریپت دستور جداگانه ای است به همین دلیل this
وجود ندارد.
** برای اینکه دستور ()user.hi
درست کار کند, جاوااسکریپت برای آن یک راه حلی دارد. عملگر نقطه '.'
نه فقط فانکشن بلکه مقدار خاصی از ریفرنس تایپ ها Reference Type را برمیگرداند **.
ریفرنس تایپ ها یا نوع ارجاعی “نوع خاصی از داده ها یا specification type” هستند. ما نمیتوانیم به صورت مستقیم از آن استفاده کنیم ولی به صورت داخلی داخل زبان تعبیه شده و استفاده میشود.
این نوع داده خاص شامل سه مقدار (base, name, strict)
هست که:
base
یک آبجکت استname
نام ویژگی آبجکت هست- اگر
use strict
تعبیه شده باشد مقدارstrict
نیز true است.
نه تنها مقدار user.hi
فانکشن نیست بلکه نوع آن از نوع Reference type هست. user.hi
در حالت strict mode به این صورت است:
// مقدار Reference Type
(user, "hi", true)
وقتی که پرانتزی در Reference type ها صدا زده میشود, همه اطلاعات مربوط به اشیاء و متد فعلی را دریافت میکند و به درستی کلمه کلیدی this
را مقداردهی میکند.
نوع Reference type یک نوع داده داخلی “واسط” با هدف انتقال اطلاعات مربوطه از عملگر نقطه .
به پرانتز است.
عملگری مانند عملگر انتساب (Assign) در hi = user.hi
خاصیت Reference type را در متغیر جدید کنار میذارد و صرفا مقدار تابع user.hi
برگردانده شده را میریزد. و سپس this
مقدار خود را از دست میدهد.
درنتیجه, تنها درصورتی مقدار this
به درستی پاس میشود که مستقیما فانکشن را با استفاده از نقطه obj.method()
یا براکت باز و بسته obj['method']()
صدا بزنیم. راه های مختلفی برای رفع این مشکل هست مثل func.bind().
خلاصه
تایپ مرجعی یا Reference Type ها نوع داده داخلی در زبان جاوااسکریپت هستند.
وقتی که یک ویژگی یا Peraperty مخصوصا توسط عملگر نقطه .
در ()obj.method
خوانده میشود, نه تنها مقدار ویژگی بلکه مقادیر خاص مانند ویژگی ها یا توابع خاص را هم برمیگرداند.
بعد از اینکه متدی فراخوانی شد, عملگر پرانتز آبجکت را دریافت و this
را مقداردهی میکند.
برای مابقی عملگر ها Reference Type تبدیل به مقدار ویژگی میشود (تابع هم همینطور).
همه مکانیزم هایی که از چشم ما پنهان هستند, خیلی کم پیش میاید که از آن را مهم بدانیم و مطلع شویم که چطور کار میکنند. مانند زمانی که یک مقد به صورت پویا از طریق آبجکت و با استفاده از عبارت ها به دست میاید.