คีย์เวิร์ดนี้

คีย์เวิร์ด 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 อ้างอิงเมื่อใช้นอกฟังก์ชันหรือบริบทของออบเจ็กต์

ออบเจ็กต์ window
ออบเจ็กต์ browser
ออบเจ็กต์ undefined