This در جاوا اسکریپت – توضیح و کاربرد + مثال

۱۳۱۴ بازدید
آخرین به‌روزرسانی: ۲۴ اردیبهشت ۱۴۰۲
زمان مطالعه: ۱۸ دقیقه
This در جاوا اسکریپت – توضیح و کاربرد + مثال

کلمه کلیدی This در جاوا اسکریپت برای ارجاع به «شی» (Object) استفاده می‌شود و کاربردهای بسیار قابل‌توجه دیگری نیز دارد. از آنجا که توابع در جاوا اسکریپت اساساً نوعی اشیا به‌حساب می‌آیند، مانند اشیا کاربر می‌تواند آن‌ها را به متغیرهایی اختصاص دهد، به توابع دیگر منتقل کند و بسیاری از عملیات دیگر را روی آن‌ها انجام دهد. توابع در جاوا اسکریپت خواص مختص به خودشان را دارند که در این میان، This یکی از آن‌ها است. در این مطلب آموزشی از مجله فرادرس قرار بر این است که اطلاعات کاملی از This در جاوا اسکریپت ارائه شود تا کاربران بتوانند به خوبی آن را درک کنند و در کدهای خود آن را به کار ببرند.

This در جاوا اسکریپت چیست؟

به طور کلی می‌توان گفت که This در زبان برنامه نویسی جاوا اسکریپت به شیئی اشاره می‌کند که تابع یک ویژگی از آن است. به زبان ساده می‌توان گفت که This به شیئی که در حال حاضر تابع را فراخوانی می‌کند ارجاع می‌دهد. کلمه کلیدی This در زبان برنامه نویسی جاوا اسکریپت در مقایسه با زبان‌های دیگر کمی متفاوت عمل می‌کند.

مقدار This در جاوا اسکریپت بیشتر با نحوه فراخوانی تابع بازگردانده می‌شود. همچنین برای کلمه کلیدی This در زبان جاوا اسکریپت، نمی‌توان آن را با انتساب تنظیم کرد و هر دفعه که تابع فراخوانی می‌شود مقدار آن ممکن است متفاوت باشد. این کلمه کلیدی بسته به نحوه استفاده از آن به اشیاء مختلف اشاره خواهد کرد.

کلمه کلیدی This در javascript

برای درک بهتر این کلمه کلیدی در همان ابتدا، اینجا مثالی بیان خواهد شد. فرض بر این است شیئی به نام counter  وجود دارد که این شی حاوی متد next()‎  خواهد بود. وقتی متد next()‎ فراخوانی می‌شود، می‌توان به این شی دسترسی داشت. قطعه کد این مثال به‌صورت زیر است.

1let counter = {
2  count: 0,
3  next: function () {
4    return ++this.count;
5  },
6};
7
8counter.next();

در درون تابع next()‎ ، کلمه کلیدی This به شی counter ارجاع می‌دهد. فراخوانی متد زیر این موضوع را بیان می‌کند.

1counter.next();

در اینجا تابع next()‎ ، ویژگی شی counter به‌حساب می‌آید. بنابراین، در داخل تابع next()‎ ، کلمه کلیدی This به شی counter ارجاع می‌دهد.

سینتکس This در جاوا اسکریپت

کلمه کلیدی This در زبان جاوا اسکریپت به صورت زیر نوشته خواهد شد:

1this

ارزش مقدار This در جاوا اسکریپت به این بستگی دارد که در چه زمینه‌ای ظاهر خواهد شد. This ممکن است که در زمینه‌های زیر ظاهر شود:

در ادامه این مقاله ظاهر شدن This در هرکدام یک از موارد فهرست فوق مورد بررسی واقع خواهند شد. همچنین شایان ذکر است که نحوه ظاهر شدن در هرکدام از موارد فوق می‌تواند در دو حالت رخ دهد. یکی از آن‌ها حالت دقیق است و دیگری حالت غیر دقیق، از این دو حالت به نام‌های حالت سخت و غیر سخت نیز نام‌برده می‌شود.

This در زمینه سراسری

در زمینه اجرای سراسری یعنی زمانی که کلمه کلیدی This خارج از توابع یا کلاس باشد یا به عبارت دیگر زمانی که This در داخل بلوک‌ها یا «توابع پیکان» (Arrow Functions) تعریف شده در محدوده جهانی یا سراسری باشد، مقداری که کلمه کلیدی This بازمی‌گردند به این بستگی دارد که زمینه اجرایی آن چه باشد. زمانی که کلمه کلیدی This در بالای اسکریپت یا قطعه کد ظاهر شود، در هر حالتی This به زمینه سراسری اشاره خواهد داشت (یعنی اگر به صورت GlobalThis ظاهر شود) و جاوا اسکریپت به صورت کلی با آن مانند اشیای سراسری برخورد می‌کند.

نکته: GlobalThis به طور کلی همان مفهوم شی سراسری را می‌رساند. این ویژگی برای همه مرورگرها و چارچوب نود جی اس صادق است، با این حال میزبان‌ها یا دستگاه‌های سمت مشتری می‌توانند مقدار متفاوت را برای GlobalThis ارائه دهند که با شی سراسری هیچ ارتباطی ندارد. مثال زیر در رابطه با کاربرد کلمه کلیدی This در زمینه سراسری یا گلوبال است:

1// In web browsers, the window object is also the global object:
2console.log(this === window); // true
3
4this.b = "MDN";
5console.log(window.b); // "MDN"
6console.log(b); // "MDN"

مثال زیر هم در رابطه با این موضوع است:

1console.log(this === window); // true

اگر خاصیتی به This در زمینه سراسری اختصاص یابد، جاوا اسکریپت همان‌طور که در مثال زیر نشان داده شده است، این ویژگی را به شی سراسری اضافه می‌کند:

1this.color= 'Red';
2console.log(window.color); // 'Red'

This در توابع جاوا اسکریپت

موضوع یا زمینه مهم دیگری که This با آن به کار می‌رود، توابع جاوا اسکریپت هستند که در این بخش مورد بررسی دقیق قرار خواهند گرفت. در جاوا اسکریپت تابع به چهار روش زیر قابل فراخوانی است:

  • «فراخوانی تابع» (Function invocation)
  • «فراخوانی متد» (Method invocation)
  • «فراخوان سازنده» (Constructor invocation)
  • «فراخوانی غیرمستقیم» (Indirect invocation)
زمینه های this در جاوا اسکریپت

کلمه کلیدی This را می‌توان از هر چهار منظر مورد بررسی قرار داد که در ادامه این مطلب این کار انجام خواهد شد.

This در فراخوانی تابع

در داخل توابع جاوا اسکریپت، کلمه کلیدی This به نحوه فراخوانی تابع بستگی دارد. در این رابطه فرض بر این است که This نوعی پارامتر پنهان است که دقیق مانند پارامترهای اعلام شده در خود تابع عمل می‌کند. برای توابع معمولی، This در جاوا اسکریپت دقیق مانند شیئی است که تابع به آن دسترسی دارد. برای مثال اگر فراخوانی تابع به صورت obj.f()‎  باشد، در این صورت This به obj  اشاره خواهد داشت. مثال زیر در رابطه با این موضوع خیلی مهم است.

1function getThis() {
2  return this;
3}
4
5const obj1 = { name: "obj1" };
6const obj2 = { name: "obj2" };
7
8obj1.getThis = getThis;
9obj2.getThis = getThis;
10
11console.log(obj1.getThis()); // { name: 'obj1', getThis: [Function: getThis] }
12console.log(obj2.getThis()); // { name: 'obj2', getThis: [Function: getThis] }

همچنین در حالت غیردقیق، وقتی تابع به صورت زیر فراخوانی می‌شود، This به شی سراسری ارجاع می‌دهد:

1function show() {
2   console.log(this === window); // true
3}
4
5show();

در مثال بالا زمانی که تابع show()‎  فراخوانی می‌شود، کلمه کلیدی This به شی سراسری اشاره می‌کند. در این مثال این شی Window  یا پنجره مرورگر است که نوعی متغیری سراسری در مرورگرهای وب و نود جی اس خواهد بود. در رابطه با این مثال، فراخوانی تابع show()‎ به صورت زیر است:

1window.show();

در حالت سخت یا غیردقیق، جاوا اسکریپت برای This تابعی را روی مقدار «تعریف نشده» (Undefined) تنظیم می‌کند. مثال زیر این موضوع را نشان می‌دهد:

1"use strict";
2
3function show() {
4    console.log(this === undefined);
5}
6
7show();

همان‌طور که مثال بالا قابل مشاهده است، برای فعال کردن حالت سخت، از دستور use strict  در ابتدای کد جاوا اسکریپت استفاده می‌شود. همچنین کاربر می‌تواند این حالت سخت را فقط برای تابعی خاص اعمال کند که در این صورت دستور نام برده را فقط در بالای بدنه آن تابع قرار می‌دهد. همچنین باید به این نکته توجه داشت که حالت سخت از زمان «ECMAScript 5.1» در دسترس قرار گرفت. حالت سخت برای توابع معمولی و توابع تودرتو قابل عمال است. مثال زیر این موضوع را نشان می‌دهد.

1function show() {
2    "use strict";
3    console.log(this === undefined); // true
4
5    function display() {
6        console.log(this === undefined); // true
7    }
8    display();
9}
10
11show();

خروجی این مثال به صورت زیر است:

true
true

در تابع داخلی display()‎  ، کلمه This همان‌طور که در کنسول نشان داده شده، روی Undefined تنظیم شده است.

چند مثال دیگر از کابرد This در فراخوانی تابع

در زیر چند مثال دیگر از This در فراخوانی تابع جاوا اسکریپت بررسی خواهد شد.

مثال ١ از کاربرد This در فراخوانی تابع:

1<!DOCTYPE html>
2<html>
3<body>
4<script>
5	function doSomething() {
6		// do something here
7	}
8
9// function invocation
10doSomething();
11</script>				
12</body>
13</html>

This در داخل تابع doSomething  ، اگر از طریق فراخوانی تابع مانند بالا فراخوانی شود، در این صورت This در جاوا اسکریپت دارای مقدار شی سراسری خواهد بود، اما همیشه هم به این صورت نیست و این بستگی به حالت دقیق یا غیر دقیق دارد که مثال ٢ در این رابطه آورده شده است.

مثال ٢ از کاربرد This در فراخوانی تابع:

1<!DOCTYPE html>
2<html>
3<body>
4<script>
5	function doSomething(a, b) {
6
7	// adds a propone property to the Window object
8		this.propone = "test value";
9	}
10
11// function invocation
12doSomething();
13document.write(window.propone);
14</script>				
15</body>
16</html>					

خروجی این مثال به صورت زیر است:

test value 

در مثال فوق اگر تابع doSomething()‎  در حالت سخت یا غیردقیق اجرا شود، This به جای شی پنجره سراسری، «تعریف نشده» (Undefine) بازگردانده خواهد شد. دلیل این کار این است که در حالت سخت، مقدار پیش‌فرض This در جاوا اسکریپت، برای هر شی تابع، به‌جای شی سراسری روی Undefine تنظیم می‌شود.

مثال ٣ از کاربرد This در فراخوانی تابع:

1<!DOCTYPE html>
2<html>
3<body>
4<script>
5	function doSomething() {
6		// enable the strict mode
7		'use strict';
8
9	// logs undefined
10		document.write(this + '<br>')
11			function innerFunction() {
12			// Also logs undefined, indicating that
13			// strict mode permeates to inner function scopes
14				document.write(this)
15			}
16		innerFunction();
17	}
18
19// function invocation
20doSomething();
21</script>				
22</body>
23</html>										

خروجی این مثال به صورت زیر خواهد بود:

undefined
undefined 

تحلیل این مثال به کاربر واگذار خواهد شد.

This در فراخوانی متد

زمانی که متدی از شیئی فراخوانی می‌شود، This در جاوا اسکریپت به شیئی که متد را در اختیار دارد، فراخوانی خواهد شد. مثال زیر این موضوع را بیان می‌کند.

1let car = {
2    brand: 'Honda',
3    getBrand: function () {
4        return this.brand;
5    }
6}
7
8console.log(car.getBrand()); // Honda

شی در این مثال car  است. در این مثال، This در متد getBrand()‎  به شی car ارجاع می‌دهد. همچنین از آنجا که متد از ویژگی‌های شی به‌حساب می‌آید، می‌توان آن را در متغیری نیز ذخیره کرد که مثال زیر در این رابطه آورده شده است.

1let brand = car.getBrand;

با این اوصاف متد از طریق متغیر به صورت زیر قابل فراخوانی است.

1console.log(brand()); // undefined

با این کار در خروجی به جای دریافت عبارت « Honda»، تعریف نشده بازگردانده خواهد شد زیرا زمانی که متدی بدون مشخص کردن شی آن فراخوانی می‌شود، This در جاوا اسکریپت با زمینه سراسری و در حالت غیردقیق بازمی‌گردند که در این حالت خروجی تعریف نشده خواهد بود.

آموزش تابع در جاوا اسکریپت

برای رفع این مشکل می‌توان از متد bind()  از شی «Function.prototype» استفاده کرد. این متد تابعی را ایجاد می‌کند که در آن کلمه کلیدی This روی مقداری مشخص تنظیم شده است. مثال زیر در رابطه با این موضوع آورده شده است.

1let brand = car.getBrand.bind(car);
2console.log(brand()); // Honda

در این مثال، زمانی که متد brand()  فراخوانی می‌شود، کلمه کلیدی This در جاوا اسکریپت به شی car ارجاع خواهد شد. مثال زیر این موضوع را نشان خواهد داد:

1let car = {
2    brand: 'Honda',
3    getBrand: function () {
4        return this.brand;
5    }
6}
7
8let bike = {
9    brand: 'Harley Davidson'
10}
11
12let brand = car.getBrand.bind(bike);
13console.log(brand());

خروجی این مثال به صورت زیر است:

Harley Davidson

در این مثال، کلمه کلیدی This متد brand()  را به شی bike  تنظیم می‌کند، بنابراین، مقدار ویژگی brand() شی bike را در کنسول نشان می‌دهد.

چند مثال از This در فراخوانی متد

زمانی که توابع به عنوان فیلدها یا خصوصیات اشیاء تعریف می‌شوند، به آن‌ها متد یا روش گفته می‌شود. در زیر چند مثال برای کلمه کلیدی This در جاوا اسکریپت به همراه متدها برای درک بهتر آورده شده است.

مثال ١ از This در فراخوانی متد:

1<!DOCTYPE html>
2<html>
3<body>
4<script>
5	let person = {
6		name : "kamel",
7		age : 28,
8		logInfo : function() {
9			document.write(this.name + " is " + this.age + " years old ");
10		}
11	}
12	person.logInfo()
13				</script>				
14</body>
15</html>									

خروجی این مثال به صورت زیر است:

kamel is 28 years old 

در قطعه کد بالا، logInfo()‎  متدی از شی person  به‌حساب می‌آید که با استفاده از الگوی فراخوانی شی، فراخوانی شده است. این یعنی که جاوا اسکریپت از ویژگی‌های accessors  برای دسترسی به متدی که بخشی از شی به‌حساب می‌آید استفاده کرده است.

برای این نوع فراخوانی باید از عبارتی استفاده کرد که شیئی که متد بخشی از آن است، را ارزیابی می‌کند. این کار به برنامه‌ نویس کمک می‌کند تا بفهمد که This در جاوا اسکریپت چه چیزی می‌تواند باشد، زیرا در هر فراخوانی ارزش This ممکن است متفاوت باشد. در داخل چنین متدی که با استفاده از دسترسی‌های ویژگی فراخوانی شده است، This مقدار شی فراخوانی را خواهد داشت، یعنی به شیئی اشاره می‌کند که همراه با دسترسی به ویژگی برای برقراری تماس استفاده شده است که مثال ٢ این موضوع را بیان خواهد کرد:

مثال ٢ از This در فراخوانی متد:

1<script>
2	let add = {
3		num : 0,
4		calc : function() {
5	
6			// logs the add object
7			document.write(this + ' ')
8				this.num
9				+= 1;
10			return this.num;
11		}
12	};
13	
14	// logs 1
15	document.write(add.calc() + '<br>');
16	// logs 2
17	document.write(add.calc());
18</script>

خروجی این مثال به صورت زیر است:

[object Object] 1
[object Object] 2 

در مثال فوق، calc()‎  متدی از شی add  است و بنابراین با استفاده از قوانین فراخوانی متد در خطوط 9 و 10 فراخوانی خواهد شد. همچنین به این نکته اشاره شد که زمانی از الگوهای فراخوانی متد استفاده شود، مقدار This در جاوا اسکریپت روی شی فراخوان تنظیم خواهد شد. در این مثال و در داخل متد calc()‎ مقدار This به شی فراخوانی تنظیم خواهد شد که در این مثال شی add است و با این کار به آسانی می‌توان به ویژگی add's num  دسترسی پیدا کرد.

کاربرد کلمه کلیدی this

با این حال، برای این موضوع مبحثی پیچیده نیز وجود دارد و سوال اصلی اینجاست که برای تابعی که درون متدی از یک شی قرار دارد، این عمل به چه صورت خواهد بود؟ مثال ٣ در این رابطه آورده شده است.

مثال ٣ از This در فراخوانی متد:

1<script>
2	let add = {
3		num : 0,
4		calc : function() {
5	
6		// logs the add object
7		document.write(this + ' ')
8	
9		function innerfunc() {
10			this.num += 1;
11	
12		// logs the window object
13		document.write(this + ' ');
14	
15		return this.num
16	
17	} return innerfunc();
18	}
19	};
20	
21	// logs NaN
22	document.write(add.calc() + '<br>');
23	
24	// logs NaN
25	document.write(add.calc());
26</script>

خروجی این مثال به صورت زیر است:

[object Object] [object Window] NaN
[object Object] [object Window] NaN 

زمانی که متد calc()‎  در خطوط 14 و 15 قطعه کد بالا فراخوانی می‌شود، از فراخوانی متد استفاده خواهد شد که This را برای add  در calc()‎  تنظیم می‌کند. این مسئله به آسانی از دستور log  در خط 4 قابل تائید است.

با این وجود، innerfunc()  از درون متد calc()‎ با استفاده از نوعی فراخوانی تابع ساده (خط 11) فراخوانی می‌شود. این یعنی که در داخل innerfunc() ، کلمه کلیدی This روی شی سراسری تنظیم می‌شود که خاصیت « Num» ندارد و از این‌ رو خروجی‌های «NaN» بازگردانده می‌شود، اما چگونه می‌توان با این چالش روبه‌رو شد؟ راه‌حل منطقی این است که This را از تابع بیرونی به متغیری اختصاص داد تا در تابع تودرتو به صورت زیر استفاده شود. مثال ٤ این موضوع را برای حل این مسئله نشان می‌دهد.

1<script>
2	let add = {
3		num : 0,
4		calc : function() {
5
6			// logs the add object
7			document.write(this + ' ')
8
9		// using thisreference variable to
10		// store the value of this
11		thisreference = this;
12
13			function innerfunc()
14			{
15
16			// using the variable to access the
17			// context of the outer function
18				thisreference.num += 1;
19
20			// logs the add object
21				document.write(thisreference + ' ');
22				return thisreference.num;
23			}
24			return innerfunc();
25		}
26	};
27	// logs 1
28	document.write(add.calc() + '<br>');
29
30	// logs 2
31	document.write(add.calc());
32</script>																

خروجی این مثال به صورت زیر است:

[object Object] [object Object] 1
[object Object] [object Object] 2 

همچنین راه‌حل‌های دیگری برای حل این مشکل وجود دارد که این راه‌حل‌ها شامل استفاده از توابع زیر است:

  • bind()
  • call()
  • application()

در این مطلب به آن‌ها پرداخته نخواهد شد.

This در فراخوانی سازنده

زمانی که از کلمه کلیدی New برای ایجاد نمونه‌ای از شی تابع استفاده می‌شود، در واقع با این کار از تابع به عنوان نوعی سازنده استفاده خواهد شد که This در جاوا اسکریپت در این رابطه هم قابل بحث است. برای درک این مطلب مثالی آورده شده که در آن تابع Car  را اعلام و سپس به عنوان نوعی سازنده این تابع فراخوانی خواهد شد. قطعه کد این مثال به صورت زیر است:

1function Car(brand) {
2    this.brand = brand;
3}
4
5Car.prototype.getBrand = function () {
6    return this.brand;
7}
8
9let car = new Car('Honda');
10console.log(car.getBrand());

در مثال فوق، عبارت new Car ('Honda')  نوعی فراخوان سازنده از تابع Car()‎ است. در این رابطه جاوا اسکریپت شیئی جدید ایجاد می‌کند و This را روی شی جدید تنظیم خواهد کرد. با این کار اکنون کاربر می‌تواند Car()‎  را به عنوان تابع یا به عنوان سازنده فراخوانی کند. همچنین اگر کلمه کلیدی New از این عبارت حذف شود به صورت زیر خواهد بود.

1var bmw = Car('BMW');
2console.log(bmw.brand);
3// => TypeError: Cannot read property 'brand' of undefined

به دلیل اینکه This در تابع Car()‎ روی شی جهانی تنظیم می‌شود، bmw.brand  تعریف نشده را بازمی‌گردند. برای اینکه اطمینان حاصل شود که تابع Car()‎ همیشه با استفاده از فراخوانی سازنده، فراخوانی می‌شود باید نوعی بررسی یا چک کردن در ابتدای تابع Car()‎ به صورت زیر اضافه شود:

1function Car(brand) {
2    if (!(this instanceof Car)) {
3        throw Error('Must use the new operator to call the function');
4    }
5    this.brand = brand;
6}

جاوا اسکریپت مدرن یا جاوا اسکریپت ES6 نوعی خاصیت اضافه به نام new.target  معرفی کرده است که به برنامه نویسان این امکان را می‌دهد که تشخیص دهند آیا تابع به عنوان تابعی ساده فراخوانی می‌شود یا به عنوان نوعی سازنده. برای مثال برای تابع Car در مثال، خاصیت new.target را به صورت زیر به کار برده شده است.

1function Car(brand) {
2    if (!new.target) {
3        throw Error('Must use the new operator to call the function');
4    }
5    this.brand = brand;
6}

مثالی از This در فراخوانی سازنده

مثال زیر نحوه استفاده از This در فراخوانی سازنده را نشان خواهد داد که در ادامه چگونگی آن تشریح خواهد شد.

1<script>
2	let people = function(name, age) {
3			this.name = name;
4			this.age = age;
5	
6		this.displayInfo = function() {
7		document.write(this.name + " is " + this.age + " years old");
8		}
9		}
10	
11	let person1
12		= new people('kamel', 28);
13	
14	person1.displayInfo();
15</script>

خروجی این مثال به صورت زیر است:

kamel is 28 years old 

تشریح این مثال از This در فراخوانی سازنده به صورت مراحل زیر است:

  1. در مثال فوق، در مرحله اول شیئی خالی ایجاد خواهد که نمونه‌ای از نام تابع است که با New استفاده می‌شود. به زبان ساده، ویژگی سازنده، شی را به تابعی که در فراخوانی استفاده شده است (people(name, age))  تنظیم می‌کند.
  2. در مرحله دوم، نمونه اولیه تابع سازنده ( people  ) را به شی جدید ایجاد شده، پیوند خواهد داد. با این کار اطمینان حاصل می‌شود که این شی می‌تواند تمام ویژگی‌ها و روش‌های تابع سازنده را به ارث ببرد.
  3. سپس، تابع سازنده بر روی این شی تازه ایجاد شده فراخوانی خواهد شد و همانند فراخوانی متد که در بالا بحث شد، داخل تابع سازنده، This در جاوا اسکریپت مقدار شی جدید ایجاد شده در فراخوانی را دریافت خواهد کرد.
  4. در مرحله آخر، شی ایجاد شده با تمام ویژگی‌ها و مجموعه متدهایش به person1  بازگردانده می‌شود.

 

This در فراخوانی غیر مستقیم

در جاوا اسکریپت با توابع به عنوان عناصری درجه یک برخورد می‌شود و توابع اشیایی از نوع «Function» به‌حساب می‌آیند. بسته به نوع تابع دو متد برای فراخوانی آن وجود دارد که این متدها call()‎  و application()‎  هستند. این متدها به برنامه نویس اجازه می‌دهند که مقدار This در جاوا اسکریپت را تنظیم کند. مثال زیر این موضوع را بیان می‌کند.

1function getBrand(prefix) {
2    console.log(prefix + this.brand);
3}
4
5let honda = {
6    brand: 'Honda'
7};
8let audi = {
9    brand: 'Audi'
10};
11
12getBrand.call(honda, "It's a ");
13getBrand.call(audi, "It's an ");

خروجی این مثال به صورت زیر است:

It's a Honda
It's an Audi

در مثال فوق، تابع getBrand()‎  به صورت غیرمستقیم با استفاده از متد call()‎  تابع getBrand()‎ فراخوانی می‌شود. در این قطعه کد، شی honda  و audi  به عنوان اولین آرگومان متد call()‎ پاس داده شده‌اند، بنابراین در هر فراخوانی brand  ، نام مربوطه دریافت می‌شود. متد application()‎  شبیه متد call()‎ است با این تفاوت که آرگومان دوم آن آرایه‌ای از آرگومان‌ها به‌حساب می‌آید.

1getBrand.apply(honda, ["It's a "]); // "It's a Honda"
2getBrand.apply(audi, ["It's an "]); // "It's a Audi"

This در توابع Arrow در جاوا اسکریپت

یکی دیگر از مباحث مهم مربوط به This در جاوا اسکریپت، بحث فراخوانی در «توابع پیکان» (Arrow functions) است. مفهوم توابع پیکان برای اولین بار در ES6 معرفی شد. توابع پیکان از لحاظ لغوی کارشان تنظیم This در جاوا اسکریپت است.

این یعنی که این توابع شرایط و زمینه اجرای خود را فراهم نمی‌کنند بلکه This را از تابع بیرونی به ارث می‌برند که این توابع بیرونی نوعی تابع پیکان تعریف شده به‌حساب می‌آیند. مثال زیر این موضوع را به خوبی نشان می‌دهد.

1let getThis = () => this;
2console.log(getThis() === window); // true

در این مثال، مقدار This روی شی سراسری یعنی پنجره در مرورگر وب تنظیم شده است. از آنجایی که توابع پیکان زمینه اجرای خود را ایجاد نمی‌کنند، تعریف متد با استفاده از این‌گونه توابع باعث ایجاد مشکل می‌شود. مثال زیر این موضوع را بیان می‌کند.

1function Car() {
2  this.speed = 120;
3}
4
5Car.prototype.getSpeed = () => {
6  return this.speed;
7};
8
9var car = new Car();
10console.log(car.getSpeed()); // 👉 undefined

در متد getSpeed()‎  ، مقدار This به شی سراسری ارجاع می‌دهد نه شی Car  ، اما شی سراسری خاصیتی به نام speed  ندارد. بنابراین، This.speed  در متد getSpeed()‎  تعریف نشده بازمی‌گردد.

توابع پیکان در جاوا اسکریپت

This در بافت کلاس

کلاس را می‌توان به دو زمینه تقسیم کرد که این زمینه‌ها کلاس استاتیک و کلاس نمونه هستند. سازنده‌ها، متدها و مقادیر اولیه فیلدهای خصوصی و عمومی به کلاس نمونه تعلق دارند. همچنین متدهای استاتیک، مقداردهی اولیه به روش استاتیک و بلوک‌های سازنده اولیه نیز متعلق به زمینه کلاس استاتیک هستند. سازنده کلاس همیشه با کلمه کلیدی NEW فراخوانی می‌شود و از همین رو رفتار آن‌ها مانند سازنده‌های توابع است.

This در زمینه کلاس مقدار نمونه جدیدی به‌حساب می‌آید که ایجاد می‌شود. به عبارت دیگر متدهای کلاس مانند متدها در حروف الفبای شی رفتار می‌کنند و This در این رابطه مقدار شیئی است که متد به آن دسترسی خواهد داشت. اگر متد به شی دیگری منتقل نشود، This در جاوا اسکریپت در این شرایط نمونه‌ای از کلاس به‌حساب می‌آید.

همچنین شایان ذکر است که متدهای ایستا نوعی ویژگی This نیستند و در واقع آن‌ها ویژگی خود کلاس به‌حساب می‌آیند. بلوک‌های سازنده اولیه استاتیک نیز با وجود ویژگی This به کلاس فعلی ارزیابی می‌شوند. همچنین مقداردهی اولیه فیلد نیز در زمینه کلاس ارزیابی می‌شود. از طرفی فیلدهای نمونه با This نیز به نمونه در حال ساخت ارزیابی می‌شوند و فیلدهای استاتیک با This به کلاس فعلی ارزیابی خواهند شد. مثال زیر در این رابطه مهم است:

1class C {
2  instanceField = this;
3  static staticField = this;
4}
5
6const c = new C();
7console.log(c.instanceField === c); // true
8console.log(C.staticField === C); // true

همانطور که قابل مشاهد است، خروجی این مثال به TRUE ارزیابی خواهد شد.

 

متدهای محدود در کلاس

دقیق مانند توابع منظم، ارزش This در متدها به نحوه فراخوانی آن‌ها بستگی دارد. در برخی از شرایط نادیده گرفتن This در جاوا اسکریپت عمل مفیدی است، به طوری که This در کلاس‌های جاوا اسکریپت همیشه به نمونه کلاس اشاره می‌کند. برای دستیابی به این هدف، باید متدهای کلاس را در سازنده پیوند داد. مثال زیر این موضوع را بیان می‌کند.

1class Car {
2  constructor() {
3    // Bind sayBye but not sayHi to show the difference
4    this.sayBye = this.sayBye.bind(this);
5  }
6  sayHi() {
7    console.log(`Hello from ${this.name}`);
8  }
9  sayBye() {
10    console.log(`Bye from ${this.name}`);
11  }
12  get name() {
13    return "Ferrari";
14  }
15}
16
17class Bird {
18  get name() {
19    return "Tweety";
20  }
21}
22
23const car = new Car();
24const bird = new Bird();
25
26// The value of 'this' in methods depends on their caller
27car.sayHi(); // Hello from Ferrari
28bird.sayHi = car.sayHi;
29bird.sayHi(); // Hello from Tweety
30
31// For bound methods, 'this' doesn't depend on the caller
32bird.sayBye = car.sayBye;
33bird.sayBye(); // Bye from Ferrari

نکته: کلاس‌ها همیشه در حالت سخت هستند. فراخوانی متدهایی با This تعریف نشده مشکل است و اگر متد سعی کند به ویژگی‌های This دسترسی پیدا کند، با خطا مواجه می‌شود.

This در کنترل کننده رویداد DOM

زمانی که تابعی از آن به عنوان «کنترل کننده رویداد» (Event Handler) یاد می‌شود، This روی عنصری تنظیم خواهد شد که «شنونده رویداد» (Event Listener) روی آن قرار دارد.

برخی از مرورگرها از این ویژگی برای شنونده رویداد پشتیبانی نمی‌کنند. مثال زیر نحوه استفاده از This در جاوا اسکریپت در شنونده رویداد را نشان می‌دهد.

1// When called as a listener, turns the related element blue
2function bluify(e) {
3  // Always true
4  console.log(this === e.currentTarget);
5  // true when currentTarget and target are the same object
6  console.log(this === e.target);
7  this.style.backgroundColor = "#A5D9F3";
8}
9
10// Get a list of every element in the document
11const elements = document.getElementsByTagName("*");
12
13// Add bluify as a click listener so when the
14// element is clicked on, it turns blue
15for (const element of elements) {
16  element.addEventListener("click", bluify, false);
17}

This در شنونده رویداد

زمانی که کد جاوا اسکریپت از ویژگی کنترل کننده رویداد درون‌خطی فراخوانی می‌شود، This در جاوا اسکریپت روی عنصر «شی سند» (Document Object) یا DOM تنظیم خواهد شد که شنونده رویداد روی آن عنصر قرار گرفته است.

قطعه کد زیر این موضوع را بیان خواهد کرد.

1<button onclick="alert(this.tagName.toLowerCase());">Show this</button>

در قطعه کد بالا button  ، alert   را نشان می‌دهد اما با این حال باید توجه کرد که این شرایط فقط برای کد بیرونی این‌گونه تنظیم می‌شود. مثال بعدی هم در این رابطه مهم است.

1<button onclick="alert((function () { return this; })());">
2  Show inner this
3</button>

در مورد این مثال باید گفت که تابع داخلی روی This تنظیم نشده است، بنابراین شی سراسری پنجره مرورگر را بازمی‌گرداند.

آموزش پایه جاوا اسکریپت

This در شنونده رویداد و کار با آن بسیار حائز اهمیت است، از این رو برنامه نویسان باید به کاربرد This در اینگونه موارد خیلی دقت کنند.

 

This با دستوارت جاوا اسکریپت

اگرچه استفاده از This با دستورات جاوا اسکریپت منسوخ شده است و در دسترس نیست، اما هنوز هم به عنوان یک استثنا از قوانین عادی از آن‌ها در مواردی خاص استفاده می‌شود.

برای مثال اگر تابعی در دستوری فراخوانی شود و آن تابع یک ویژگی شی scope  باشد، مقدار This به شی scope تنظیم می‌شود. مثال زیر این موضوع را نشان می‌دهد.

1const obj1 = {
2  foo() {
3    return this;
4  },
5};
6
7with (obj1) {
8  console.log(foo() === obj1); // true
9}

به کاربردن This با Getter و Setter در جاوا اسکریپت

مقدار This در جاوا اسکریپت هنگام به‌کارگیری آن با «دریافت‌کننده‌ها» (Getter) و «تنظیم‌کننده‌ها» (Setter) به این بستگی دارد که بر روی کدام شی قابل‌دسترس است نه اینکه ویژگی بر روی کدام شی تعریف می‌شود.

در این رابطه تابعی که به عنوان دریافت‌کننده‌ و تنظیم‌کننده‌ استفاده شده محدود خواهد شد به شیئی که ویژگی This روی آن تنظیم یا دریافت می‌شود. مثال زیر در این رابطه آروده شده است:

1function sum() {
2  return this.a + this.b + this.c;
3}
4
5const o = {
6  a: 1,
7  b: 2,
8  c: 3,
9  get average() {
10    return (this.a + this.b + this.c) / 3;
11  },
12};
13
14Object.defineProperty(o, "sum", {
15  get: sum,
16  enumerable: true,
17  configurable: true,
18});
19
20console.log(o.average, o.sum); // 2, 6

همانطور که مشاهد شد، This در جاوا اسکریپت برای کار با Getter و Setter نیز بسیار حائز اهمیت است.

 

This و تبدیل شی در جاوا اسکریپت

در حالت غیردقیق یا در حالت سخت، اگر تابعی با مقداری فراخوانی شود که این مقدار شی نیست، در نتیجه مقدار گفته شده با یک شی در جاوا اسکریپت جایگزین خواهد شد. بنابراین null و Undefined به GlobalThis تبدیل خواهند شد. در این حالت عناصری مانند 7  یا foo  با استفاده از سازنده مربوطه به شی تبدیل می‌شوند.

برای مثال در این مورد داده عددی 7 به کلاس بسته‌بندی «Number» و رشته foo به کلاس «Wrapper String» تبدیل خواهد شد.

1function bar() {
2  console.log(Object.prototype.toString.call(this));
3}
4
5bar.call(7); // [object Number]
6bar.call("foo"); // [object String]
7bar.call(undefined); // [object Window]

مثال بالا برای درک این مفهوم بسیار مهم است.

 

This با متد bind در جاوا اسکریپت

فراخوانی تابعی مانند f.bind(someObject)  تابعی جدید با همان بدنه و دامنه ایجاد می‌کند، اما مقدار This در جاوا اسکریپت در این‌گونه موارد به‌طور دائم به اولین آرگومان bind  محدود خواهد شد.

صرف‌نظر از اینکه تابع چگونه فراخوانی می‌شود، این اتفاق رخ خواهد داد. مثال زیر در این رابطه بسیار مهم است.

1function f() {
2  return this.a;
3}
4
5const g = f.bind({ a: "azerty" });
6console.log(g()); // azerty
7
8const h = g.bind({ a: "yoo" }); // bind only works once!
9console.log(h()); // azerty
10
11const o = { a: 37, f, g, h };
12console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty

سؤالات متداول

در این بخش از مطلب 2 پرسش و پاسخ مهم در رابطه با This در جاوا اسکریپت مطرح خواهد شد تا به کاربران درک بهتری از This در زبان برنامه نویسی جاوا اسکریپت بدهد.

دلیل استفاده از This در جاوا اسکریپت چیست؟

در جاوا اسکریپت، This به کاربر اجازه می‌دهد که از توابع در بافت‌های مختلف اجرایی استفاده مجدد کند. به این معنی که تابعی پس از تعریف می‌تواند برای شی‌های مختلف با استفاده از This فراخوانی شود و این مهم‌ترین کاربرد کلمه This در جاوا اسکریپت به حساب می‌آید.

کار This در جاوا اسکریپت چیست؟

در تابع، متد و سازنده، This نوعی ارجاع به شی فعلی محسوب می‌شود. با استفاده از This می‌توان به هر عضو شی فعلی از داخل تابع، متد و سازنده مراجعه کرد.

سخن پایانی

همان‌طور که گفته شد، کلمه کلیدی This در جاوا اسکریپت به شیئی اشاره دارد که قطعه کد فعلی را اجرا می‌کند. در واقع کلمه کلیدی This، اجرای برنامه را به شیئی که تابع فعلی را اجرا می‌کند ارجاع خواهد داد. اگر تابعی که به آن ارجاع داده می‌شود تابعی منظم باشد، This به شی سراسری اشاره می‌کند. در این مطلب آموزشی از مجله فرادرس در رابطه با This و رسالت آن در کدنویسی جاوا اسکریپت مطالب کامل و مفیدی ارائه شد. This می‌تواند در بافت‌های مختلفی مانند بافت سراسری، بافت تابع و متد، بافت کلاس و غیره به کار گرفته شود که در مطلب فوق برای هرکدام توضیحاتی همراه با مثال ارائه شد.

بر اساس رای ۱۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
Developer.MozillaGeeksForGeeksJavascriptTutorial
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *