This در جاوا اسکریپت؛ مفهوم + کاربرد
اگر سابقه کار در حیطه برنامهنویسی و به ویژه زبانهای شیگرا داشته باشید، قطعاً نام کلمه کلیدی This را شنیدهاید. معمولاً This به کلاسی که در آن تعریف میشود اشاره دارد. برخی تصور میکنند که اگر This در یک تابع نوشته شود، پس به آن تابع اشاره دارد. درحالیکه چنین چیزی نیست! عملکرد این کلمه اگر در یک تابع نوشته شود به آن بستگی دارد که تابع به چه صورت فراخوانی شود. بنابراین، رفتار این کلیدواژه در یک تابع همیشه یکسان نخواهد بود. صحبت راجعبه This در جاوا اسکریپت بسیار زیاد است؛ پس اگر علاقمند به کسب اطلاعات بیشتر هستید، در ادامه همراه ما باشید.
هرآنچه که باید درباره This در جاوا اسکریپت بدانید!
کلیدواژه This در جاوا اسکریپت به منظور ارجاع به «شی» یا Object کارایی دارد. توابع در جاوا اسکریپت در ذات خود نوعی از اشیا یا آبجکتها هستند و میتوان به آنها متغیرهایی را اختصاص و عملیات مختلفی را روی آنها انجام داد. مقدار This عمدتاً فراخوانی تابع بازگردانده خواهد شد. همچنین، هر دفعه که تابع فراخوانی میشود، مقدار This میتواند تغییر کند. به مثال زیر توجه کنید:
const test = {
prop: 42,
func: function () {
return this.prop;
},
};
console.log(test.func());
// Expected output: 42
مقداردهی به This در جاوا اسکریپت
مقداری که برای This تعریف میشود در حالت غیردقیق و آسان (non–strict mode ) همیشه به یک شی (object) اشاره خواهد داشت. در حالت دقیق و سختگیرانه (strict mode)، مقدار آن متغیر است.
نکته! Strict Mode حالتی است که در آن کدها با شرایط سختگیرانهتری اجرا میشوند. همچنین اگر یک ویژگی منسوخ شده باشد، در این حالت خطا ایجاد میکند. ازاینرو، Strict Mode موجب کاهش باگها و بهبود امنیت و عملکرد کلی برنامه خواهد شد.
مقداری که برای کلیدواژه This تعیین میشود بستگی به این دارد که در تابع ظاهر میشود یا در یک کلاس خاص و یا در زمینه سراسری؛ اما منظور چیست؟ در ادامه، در نحوه مقداردهی This در جاوا اسکریپت بررسی بیشتری خواهیم کرد.
پیشنهاد مطالعه: Node.js دقیقاً چیست؟ «یک راهنمای جامع برای مبتدیان»
This در بافت توابع در جاوا اسکریپت
مقدار This در توابع، وابسته به نحوه فراخوانی توابع است. فراخوانی توابع به ۴ شیوه مختلف انجام میشود. این ۴ شیوه عبارتاند از «فراخوانی عادی توابع» (Function invocation)، «فراخوانی سازنده» (Constructor invocation)، «فراخوانی متد» (Method invocation) و «فراخوانی غیرمستقیم» (Indirect invocation).
زمانی که This در جاوا اسکریپت برای یک تابع معمولی در نظر گرفته میشود، مقدار آن همان شیئی خواهد بود که تابع به آن دسترسی دارد. به بیان دیگر، اگر فرم فراخوانی تابع به صورت obj.f() است، مقدار This برابر با obj. خواهد بود. به مثال زیر توجه کنید:
const obj3 = {
__proto__: obj1,
name: "obj3",
};
console.log(obj3.getThis()); // { name: 'obj3' }
توجه کنید که تابع یکسان است، اما براساس نحوه فراخوانی مقدار This تغییر میکند. مقدار This برابر با شیئی که به عنوان یکی از خاصیتهای تابع (property) در بدنه آن وجود دارد نیست، بلکه This به شیئی اشاره دارد که تابع توسط آن فراخوانی شده است. به مثال زیر توجه کنید:
const obj4 = {
name: "obj4",
getThis() {
return this;
},
};
const obj5 = { name: "obj5" };
obj5.getThis = obj4.getThis;
console.log(obj5.getThis()); // { name: 'obj5', getThis: [Function: getThis] }
اگر مقداری که متد به آن دسترسی دارد یک مقدار اولیه باشد، مقداری که This به آن اشاره دارد نیز یک مقدار اولیه خواهد بود؛ اما تنها در زمانی که تابع در حالت دقیق (strict mode) باشد.
function getThisStrict() {
"use strict"; // Enter strict mode
return this;
}
// Only for demonstration — you should not mutate built-in prototypes
Number.prototype.getThisStrict = getThisStrict;
console.log(typeof (1).getThisStrict()); // "number"
اگر تابع بدون اینکه به ویژگی یا خاصیتی دسترسی داشته باشد فراخوانی شود، مقدار This در جاوا اسکریپت برابر با undefined خواهد بود؛ تنها زمانی This چنین رفتاری از خود نشان میدهد که تابع در حالت دقیق (strict mode) باشد.
console.log(typeof getThisStrict()); // "undefined"
در حالت غیردقیق یک فرایند خاصی تحت عنوان this substitution یا جایگزینی This وجود دارد که به کمک آن مقدار This همیشه برابر با یک شی خواهد بود:
- اگر تابعی با This فراخوانی شود و مقدار This برابر با undefined یا null شود، مقدار This با This سراسری (globalThis) جایگزین خواهد شد.
- اگر تابع با This فراخوانی شود و مقدار This برابر با مقدار اولیه باشد، مقدار This با مقدار اولیه شی (wrapper object) جایگزین خواهد شد.
function getThis() {
return this;
}
// Only for demonstration — you should not mutate built-in prototypes
Number.prototype.getThis = getThis;
console.log(typeof (1).getThis()); // "object"
console.log(getThis() === globalThis); // true
علاوهبراین، میتوانید مقدار This را با کمک متدهای Function.prototype.call()، Function.prototype.apply() یا Reflect.apply() نیز تعریف کنید. با استفاده از متد Function.prototype.bind() میتوانید یک تابع جدید با مقدار مشخصی برای This بسازید که وابسته به نحوه فراخوانی تابع نباشد و مقدار آن تغییر نکند. اگر از این متدها برای تعریف مقدار This استفاده کنید، قانون جایگزینی This که در قسمت قبلی گفتیم، اگر تابع از نوع غیر دقیق (non-strict) باشد، اجرا میشود.
پیشنهاد مطالعه: فیلتر در جاوا اسکریپت: بیان ساده + مثال عملی
This در جاوا اسکریپت در بافت توابع پیکان
در ادامه، نگاهی بر نحوه مقداردهی به This در جاوا اسکریپت در تابعهای پیکان (Arrow functions ) خواهیم داشت.
توابع پیکان از نظر لغوی وظیفه تنظیم This در جاوا اسکریپت را دارند. بهاین معنا که توابع پیکان شرایط و زمینه اجرای خود را فراهم نمیکنند، بلکه وظیفه دارند This را از تابع بیرونی به ارث ببرند که این توابع بیرونی نوعی تابع پیکان محسوب میشوند.
هنگام فراخوانی توابع پیکان با استفاده از call(), bind(), or apply()، پارامتر thisArg نادیده گرفته میشود. به مثال زیر توجه کنید:
const globalObject = this;
const foo = () => this;
console.log(foo() === globalObject); // true
const obj = { name: "obj" };
// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true
// Attempt to set this using bind
const boundFoo = foo.bind(obj);
console.log(boundFoo() === globalObject); // true
This در جاوا اسکریپت در بافت فراخوانی سازنده
زمانی که از کلمه کلیدی New به منظور ساخت نمونهای از شی تابع استفاده میشود، با این کار تابع از نوعی سازنده استفاده میکند. برای درک بهتر نحوه عمکرد This در جاوا اسکریپت در بافت فراخوانی از نوع سازنده به مثال زیر توجه کنید:
function C() {
this.a = 37;
}
let o = new C();
console.log(o.a); // 37
function C2() {
this.a = 37;
return { a: 38 };
}
o = new C2();
console.log(o.a); // 38
اگر یک تابع با متد super.method() فراخوانی شود، مقدار This که درون تابع وجود دارد برابر با مقدار خارج از super.method() است؛ اما برابر با شی که super به آن اشاره دارد نخواهد بود. به این دلیل که super.method یک عضو از شی نیست و سینتکس یا نوشتار و همچنین قوانین مخصوص به خود را دارد.
class Foo {
constructor(name) {
this.name = name;
}
getNameSeparator() {
return '-';
}
}
class FooBar extends Foo {
constructor(name, index) {
super(name);
this.index = index;
}
getFullName() {
return this.name + super.getNameSeparator() + this.index;
}
}
const firstFooBar = new FooBar('foo', 1);
console.log(firstFooBar.name);
// Expected output: "foo"
console.log(firstFooBar.getFullName());
// Expected output: "foo-1"
پیشنهاد مطالعه: آموزش تست نویسی جاوا اسکریپت به زبان ساده
This در بافت کلاس در جاوا اسکریپت
کلاسها به دو دسته استاتیک و نمونه قابل تقسیمبندی هستند. متدها، سازندهها و مقادیر اولیه فیلدهای عمومی و خصوصی متعلق به کلاس نمونه هستند. درمقابل، متدهای استاتیک، بلوکهای سازنده اولیه و مقداردهی به روش استاتیک مربوط به کلاس استاتیک خواهند بود. سازنده کلاس همیشه با کلیدواژه NEW فراخوانی میشود؛ بههمین علت رفتار آنها مشابه با سازندههای توابع است.
This در کلاس نمونه یک مقدار جدید به حساب میآید. به بیان دیگر، متدهای کلاس مثل متدها در حروف الفبای شی رفتار میکنند و This در جاوا اسکریپت مقدار شیئی خواهد بود که متد به آن دسترسی دارد. چنانچه متد به یک شی دیگر منتقل نشود، در این شرایط This نمونهای از کلاس محسوب خواهد شد.
توجه داشته باشید که متدهای ایستا نوعی ویژگی برای This نیستند، بلکه ویژگی خودِ کلاس محسوب میشوند. بلوکهای سازنده اولیه استاتیک با وجود ویژگی This با کلاس فعلی ارزیابی خواهند شد. مقداردهی اولیه فیلد نیز در زمینه کلاس ارزیابی میشود. از سوی دیگر، فیلدهای نمونه با This با نمونه درحال ساخت قابل ارزیابی هستند و فیلدهای استاتیک با This در کلاس فعلی ارزیابی میشوند. به مثال زیر توجه کنید:
class C {
instanceField = this;
static staticField = this;
}
const c = new C();
console.log(c.instanceField === c); // true
console.log(C.staticField === C); // true
برخلاف سازنده کلاس پایه، سازندگان کلاس مشتق شده چنین عملکردی ندارند. متد super یک اتصال با سازنده ایجاد میکند و همچون مثال زیر ارزیابی میشود:
class Base {}
class Good extends Base {}
class AlsoGood extends Base {
constructor() {
return { a: 5 };
}
}
class Bad extends Base {
constructor() {}
}
new Good();
new AlsoGood();
new Bad(); // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
This در زمینه سراسری
This در جاوا اسکریپت در زمینه سراسری یا Global به این معناست که کلیدواژه This خارج از توابع یا کلاس باشد. به عبارت دیگر، زمانی که This درون بلوکها یا توابع پیکان در محدوده جهانی یا سراسری تعریف شود، مقدار یکه برمیگرداند به زمینه اجرایی آن بستگی دارد.
هنگامی که کلمه کلیدی This در بالای اسکریپت قطعه کد نوشته شود، This در هر حالتی به زمینه سراسری اشاره دارد و به صورت GlobalThis ظاهر میشود. در چنین شرایطی، جاوا اسکریپت با آن مثل اشیای سراسری رفتار خواهد کرد.
نکته! منظور از GlobalThis همان مفهوم شی سراسری است. این ویژگی برای همه مرورگرها و چهارچوب Node.js صدق میکند. اما میزبانها یا دستگاههای سمت کاربر میتوانند مقدار متغیری برای GlobalThis ارائه کنند که هیچگونه ارتباطی با شی سراسری ندارد. به مثال زیر توجه کنید:
// In web browsers, the window object is also the global object:
console.log(this === window); // true
this.b = "MDN";
console.log(window.b); // "MDN"
console.log(b); // "MDN"
چنانچه منبع به عنوان یک ماژول بارگذاری شود (در Html اضافه کردن type=”module” در تگ <script>) مقدار This همیشه برابر با undefined خواهد بود. اگر منبع با eval() اجرا شود، مقدار This برابر با globalThis خواهد بود. به مثال زیر توجه کنید:
function test() {
// Direct eval
console.log(eval("this") === this);
// Indirect eval, non-strict
console.log(eval?.("this") === globalThis);
// Indirect eval, strict
console.log(eval?.("'use strict'; this") === globalThis);
}
test.call({ name: "obj" }); // Logs 3 "true"
آموزش جاوا اسکریپت در مکتب خونه
جاوا اسکریپت یکی از مهمترین زبانهای برنامهنویسی محسوب میشود که مفاهیم بسیار زیاد و مهمی دارد. با شناخت این مفاهیم و یادگیری کاربرد هر یک از آنها میتوانید به شیوهای درست و منطقی کدنویسی کنید. یکی از مهمترین مفاهیم This در جاوا اسکریپت است که وظیفه دارد به یک شی تحت شرایط خاص اشاره کند.
مفاهیمی که در رابطه با This وجود دارد بسیار گسترده است و ما در این راهنما سعی کردیم مهمترینِ آنها را پوشش دهیم. اگر علاقمند به کسب اطلاعات بیشتر درباره جاوا اسکریپت و اطلاعات تکمیلی در مورد This و سایر کلیدواژههای مهم در جاوا اسکریپت هستید، از شما دعوت میشود سری به دورههای آموزش جاوا اسکریپت و آموزش برنامه نویسی در مکتب خونه بزنید.