คีย์เวิร์ด this หมายถึงค่าของออบเจ็กต์ที่เชื่อมโยงกับฟังก์ชัน ณ เวลาเรียกใช้ ซึ่งหมายความว่าค่าของคีย์เวิร์ดจะแตกต่างกันไปโดยขึ้นอยู่กับว่ามีการเรียกใช้ฟังก์ชันเป็นเมธอด เป็นฟังก์ชันสแตนด์อโลน หรือเป็นคอนสตรัคเตอร์
เมื่อมีการเรียกใช้ฟังก์ชัน ระบบจะสร้างอินสแตนซ์ของคีย์เวิร์ด this ขึ้นเบื้องหลังเพื่ออ้างอิงถึงออบเจ็กต์ที่มีฟังก์ชันนั้น ซึ่งจะให้สิทธิ์เข้าถึงพร็อพเพอร์ตี้และเมธอดที่กําหนดไว้ควบคู่กันจากภายในขอบเขต
การใช้ this คล้ายกับการใช้ตัวแปรที่ประกาศด้วย const ในบางแง่ เช่นเดียวกับค่าคงที่ this จะนำออกไม่ได้และไม่สามารถกำหนดค่าใหม่ได้ แต่สามารถแก้ไขเมธอดและพร็อพเพอร์ตี้ของออบเจ็กต์ที่คีย์เวิร์ด this มีได้
การเชื่อมโยงส่วนกลาง
นอกฟังก์ชันหรือบริบทของออบเจ็กต์ this จะอ้างอิงถึงพร็อพเพอร์ตี้ globalThis ซึ่งเป็นการอ้างอิงถึงออบเจ็กต์ส่วนกลางในสภาพแวดล้อม JavaScript ส่วนใหญ่ ในบริบทของสคริปต์ที่ทำงานในเว็บเบราว์เซอร์ ออบเจ็กต์ส่วนกลางคือออบเจ็กต์ window ดังนี้
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
ใน Node.js globalThis คือออบเจ็กต์ global
$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}
นอกโหมดที่เข้มงวด this จะหมายถึงออบเจ็กต์ส่วนกลางภายในฟังก์ชันสแตนด์อโลนด้วย เนื่องจาก Window หลักคือออบเจ็กต์ที่ "เป็นเจ้าของ" ฟังก์ชันเหล่านั้นอย่างมีประสิทธิภาพ
function myFunction() {
console.log( this );
}
myFunction();
> Window {...}
(function() {
console.log( this );
}());
> Window {...}
เมื่อใช้โหมดเข้มงวด this จะมีค่าเป็น undefined ภายในฟังก์ชันแบบสแตนด์อโลน ดังนี้
(function() {
"use strict";
console.log( this );
}());
> undefined
ก่อนเปิดตัวโหมดที่เข้มงวด ค่า null หรือ undefined สำหรับ this จะแทนที่ด้วยการอ้างอิงไปยังออบเจ็กต์ส่วนกลาง บางครั้งคุณอาจเห็นการเชื่อมโยงส่วนกลางเรียกว่า "การเชื่อมโยงเริ่มต้น" เนื่องจากลักษณะการทำงานเดิมนี้
การเชื่อมโยงโดยนัย
เมื่อเรียกใช้ฟังก์ชันเป็นเมธอดของออบเจ็กต์ อินสแตนซ์ของ this ภายในเมธอดนั้นจะอ้างอิงออบเจ็กต์ที่มีเมธอดนั้น ซึ่งจะให้สิทธิ์เข้าถึงเมธอดและพร็อพเพอร์ตี้ที่อยู่ข้างๆ ดังนี้
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
ดูเหมือนว่าค่าของ this จะขึ้นอยู่กับวิธีกำหนดฟังก์ชันและออบเจ็กต์ที่ล้อมรอบ แต่บริบทของค่า this คือบริบทการเรียกใช้ปัจจุบัน ในกรณีนี้ บริบทการดําเนินการคือออบเจ็กต์ myObject เรียกใช้เมธอด myMethod ดังนั้น myObject คือค่าสําหรับ this ข้อมูลนี้อาจดูเป็นเทคนิคเฉพาะในบริบทของตัวอย่างก่อนหน้านี้ แต่สำหรับการใช้งาน this ขั้นสูงขึ้น ความแตกต่างนี้เป็นสิ่งที่ควรคํานึงถึง
โดยทั่วไป ให้ใช้ this ในลักษณะที่ไม่คาดหวังว่าโค้ดรอบข้างจะมีโครงสร้างที่เฉพาะเจาะจง ข้อยกเว้นของกฎนี้คือ ฟังก์ชันลูกศร ES5
this ในฟังก์ชันลูกศร
ในฟังก์ชันลูกศร
this จะได้รับการแก้ไขเป็นบอนด์ในสภาพแวดล้อมที่ล้อมรอบเชิงนิพจน์ ซึ่งหมายความว่า this ในฟังก์ชันลูกศรจะอ้างอิงถึงค่าของ this ในบริบทที่ปิดล้อมโดยรอบที่ใกล้ที่สุดของฟังก์ชันนั้น ดังนี้
let myObject = {
myMethod() { console.log( this ); },
myArrowFunction: () => console.log( this ),
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
myObject.myArrowFunction();
> Window {...}
ในตัวอย่างนี้ myObject.myMethod() จะบันทึก myObject เป็นออบเจ็กต์ที่ "เป็นเจ้าของ" เมธอดนั้น แต่ myObject.myArrowFunction() จะแสดงผล globalThis (หรือ undefined) เนื่องจากอินสแตนซ์ของ this ภายในฟังก์ชันลูกศรจะอ้างอิงถึงขอบเขตที่ล้อมรอบสูงสุดแทน
ในตัวอย่างต่อไปนี้ myEnclosingMethod จะสร้างฟังก์ชันลูกศรในออบเจ็กต์ที่มีฟังก์ชันดังกล่าวเมื่อมีการเรียกใช้ ตอนนี้อินสแตนซ์ของ this ในฟังก์ชันลูกศรจะอ้างอิงถึงค่าของ this ภายในสภาพแวดล้อมที่ล้อมรอบ ซึ่งเป็นเมธอดที่มีฟังก์ชันลูกศรนั้น เนื่องจากค่าของ this ภายใน myEnclosingMethod อ้างอิงถึง myObject หลังจากคุณกำหนดฟังก์ชันลูกศรแล้ว this ภายในฟังก์ชันลูกศรก็จะอ้างอิงถึง myObject ด้วย
let myObject = {
myMethod() { console.log( this ); },
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
การเชื่อมโยงที่ชัดเจน
การเชื่อมโยงโดยนัยจะจัดการ Use Case ส่วนใหญ่สำหรับการทำงานกับ this อย่างไรก็ตาม บางครั้งคุณอาจต้องใช้ค่าของ this เพื่อแสดงบริบทการเรียกใช้ที่เฉพาะเจาะจงแทนบริบทที่คาดคะเน ตัวอย่างที่แสดงให้เห็นถึงการทำงาน (อาจล้าสมัยไปหน่อย) คือการทำงานกับ this ภายในฟังก์ชัน Callback ของ setTimeout เนื่องจาก Callback นี้มีบริบทการเรียกใช้ที่ไม่ซ้ำกัน
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
myObject.myMethod();
> "This is my string."
setTimeout( myObject.myMethod, 100 );
> undefined
แม้ว่าข้อบกพร่องที่เฉพาะเจาะจงนี้ของ setTimeout ได้รับการแก้ไขแล้วด้วยฟีเจอร์อื่นๆ แต่ปัญหาที่คล้ายกันของการ "สูญเสีย" this ได้รับการแก้ไขแล้วก่อนหน้านี้ด้วยการสร้างการอ้างอิงอย่างชัดเจนถึงค่าของ this ภายในขอบเขตของบริบทที่ต้องการ ในบางครั้ง คุณอาจเห็นอินสแตนซ์ของ this ได้รับการกําหนดให้กับตัวแปรโดยใช้ตัวระบุ เช่น that, self หรือ _this ในฐานโค้ดเดิม รูปแบบตัวระบุทั่วไปเหล่านี้สําหรับตัวแปรที่มีค่า this ที่ส่งผ่าน
เมื่อคุณเรียกใช้ฟังก์ชันโดยใช้เมธอด call(), bind() หรือ apply()
this จะอ้างอิงออบเจ็กต์ที่เรียกใช้อย่างชัดเจน ดังนี้
let myFunction = function() {
console.log( this.myValue );
}
let myObject = {
"myValue" : "This is my string."
};
myFunction.call( myObject );
> "This is my string."
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."
การเชื่อมโยงที่ชัดเจนจะลบล้างค่า this ที่การเชื่อมโยงโดยนัยระบุ
let myObject = {
"myValue" : "This string sits alongside myMethod.",
myMethod() {
console.log( this.myValue );
}
};
let myOtherObject = {
"myValue" : "This is a string in another object entirely.",
};
myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."
หากเรียกใช้ฟังก์ชันในลักษณะที่จะตั้งค่า this เป็น undefined หรือ null ระบบจะแทนที่ค่านั้นด้วย globalThis นอกโหมดที่เข้มงวด ดังนี้
let myFunction = function() {
console.log( this );
}
myFunction.call( null );
> Window {...}
ในทํานองเดียวกัน หากเรียกใช้ฟังก์ชันในลักษณะที่จะให้ค่าพื้นฐานแก่ this ระบบจะแทนที่ค่านั้นด้วยออบเจ็กต์ Wrapper ของค่าพื้นฐานนอกโหมดที่เข้มงวด
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> Number { 10 }
ในโหมดที่เข้มงวด ระบบจะไม่บังคับให้ค่า this ที่ส่งเป็นออบเจ็กต์ไม่ว่าในกรณีใดก็ตาม แม้ว่าจะเป็นค่าพื้นฐาน null หรือ undefined ก็ตาม
"use strict";
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> 10
myFunction.call( null );
> null
new การเชื่อมโยง
เมื่อใช้ class เป็นคอนสตรัคเตอร์โดยใช้คีย์เวิร์ด new this จะอ้างอิงอินสแตนซ์ที่สร้างขึ้นใหม่ ดังนี้
class MyClass {
myString;
constructor() {
this.myString = "My string.";
}
logThis() {
console.log( this );
}
}
const thisClass = new MyClass();
thisClass.logThis();
> Object { myString: "My string." }
ในทำนองเดียวกัน ค่าของ this ภายในฟังก์ชันคอนสตรัคเตอร์ที่เรียกใช้โดยใช้ new จะอ้างอิงถึงออบเจ็กต์ที่สร้าง
function MyFunction() {
this.myString = "My string.";
this.logThis = function() {
console.log( this );
}
}
const myObject = new MyFunction();
myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }
การเชื่อมโยงเครื่องจัดการเหตุการณ์
ในบริบทของตัวแฮนเดิลเหตุการณ์ ค่าของ this จะอ้างอิงออบเจ็กต์ที่เรียกใช้ตัวแฮนเดิลนั้น ภายในฟังก์ชัน Callback ของตัวแฮนเดิลเหตุการณ์ this จะอ้างอิงองค์ประกอบที่เชื่อมโยงกับตัวแฮนเดิล ดังนี้
let button = document.querySelector( "button" );
button.addEventListener( "click", function( event ) { console.log( this ); } );
เมื่อผู้ใช้โต้ตอบกับ button ในข้อมูลโค้ดที่ติดทั่วเว็บไซต์ก่อนหน้า ผลลัพธ์ที่ได้คือออบเจ็กต์องค์ประกอบที่มี <button> ดังนี้
> Button {}
เมื่อใช้ฟังก์ชันลูกศรเป็น Callback ของ Listener เหตุการณ์ บริบทการเรียกใช้ที่ใกล้เคียงที่สุดจะระบุค่าของ this อีกครั้ง ที่ระดับบนสุด this ภายในฟังก์ชัน Callback ของตัวแฮนเดิลเหตุการณ์จะมีลักษณะดังนี้globalThis
let button = document.querySelector( "button" );
button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined
เช่นเดียวกับออบเจ็กต์อื่นๆ เมื่อคุณใช้เมธอด call(), bind() หรือ apply() เพื่ออ้างอิงฟังก์ชัน Callback ของ Listener เหตุการณ์ this จะอ้างอิงออบเจ็กต์อย่างชัดเจน ดังนี้
let button = document.querySelector( "button" );
let myObject = {
"myValue" : true
};
function handleClick() {
console.log( this );
}
button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }
ทดสอบความเข้าใจ
สคริปต์ที่ทำงานในเว็บเบราว์เซอร์ใช้ออบเจ็กต์ส่วนกลางใดที่ this อ้างอิงเมื่อใช้นอกฟังก์ชันหรือบริบทของออบเจ็กต์
windowbrowserundefined