การสูญเสียบริบท (context) ใน JavaScript
สมมติว่าเรามีฟังก์ชันภายในฟังก์ชัน ลองเรียก
ฟังก์ชันด้านนอกว่า parent และ
ฟังก์ชันด้านในว่า child:
function parent() {
function child() {
}
}
จากบทเรียนก่อนหน้า คุณทราบดีว่า หากกำหนดตัวแปร ใดๆ ในฟังก์ชันภายนอก มันจะ สามารถเข้าถึงได้ในฟังก์ชันภายใน:
function parent() {
let str = 'abcde';
function child() {
console.log(str); // จะแสดง 'abcde'
}
child(); // เรียกใช้ฟังก์ชันภายใน
}
parent(); // เรียกใช้ฟังก์ชันภายนอก
อย่างไรก็ตาม มีข้อปลีกย่อย: ฟังก์ชันภายในสามารถ
เข้าถึงตัวแปรทั้งหมดของฟังก์ชันภายนอกได้ แต่ไม่สามารถ
เข้าถึง this ได้ นั่นคือ: หาก
ฟังก์ชันภายนอกถูกผูกกับ element DOM ตัวใดตัวหนึ่ง
แล้ว this ในฟังก์ชันนั้นจะชี้ไปที่
element นั้น แต่ this ของฟังก์ชัน
ภายในจะไม่ชี้!
แล้ว this ของฟังก์ชันภายในจะชี้ไปที่อะไรล่ะ?
คำตอบ: มันจะเท่ากับ
undefined (ในโหมด strict) เนื่องจาก
ฟังก์ชันไม่ได้ถูกผูกกับอะไรเลย
ลองทดสอบในทางปฏิบัติ สมมติว่าเรามี input:
<input id="elem" value="text">
ลองผูกฟังก์ชัน parent กับ input นี้
ซึ่งจะถูกเรียกเมื่อ input สูญเสียโฟกัส:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
// จะถูกเรียกเมื่อสูญเสียโฟกัส:
function parent() {
// จะมีโค้ดบางอย่างตรงนี้
function child() {
// จะมีโค้ดบางอย่างตรงนี้
}
child(); // เรียกฟังก์ชันลูก
}
ลองแสดงเนื้อหาของ this ไปยัง
console ในสองตำแหน่ง: ภายในฟังก์ชัน parent
และภายในฟังก์ชัน child:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this); // จะแสดงลิงก์ไปยัง input ของเรา
function child() {
console.log(this); // จะแสดง undefined
}
child();
}
รันโค้ดนี้ ลองทำให้ input สูญเสียโฟกัส
แล้วดูใน console - คุณจะเห็นว่า
console.log แรกจะแสดงใน console
ลิงก์ไปยัง input ของเรา ส่วนอันที่สอง - จะแสดงแค่ undefined
สถานการณ์เช่นนี้ เมื่อ this ชี้ไปไม่ถูกต้องตามที่เราต้องการ
อย่างไม่คาดคิด เรียกว่า การสูญเสียบริบท
สมมติว่าตอนนี้ทั้งในฟังก์ชันแรกและฟังก์ชันที่สอง
เราจะแสดง value ของ input ลองกำหนดดูว่า
อะไรจะถูกแสดงในบรรทัดของโค้ดที่ทำเครื่องหมายด้วย
ความคิดเห็น:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this.value); // จะแสดงอะไร?
function child() {
console.log(this.value); // จะแสดงอะไร?
}
child();
}