การสูญเสียบริบท (context) ใน JavaScript

สมมติว่าเรามีฟังก์ชันภายในฟังก์ชัน ลองเรียก ฟังก์ชันด้านนอกว่า parent และ ฟังก์ชันด้านในว่า child:

javascriptfunction parent() {
  function child() {
    
  }
}

จากบทเรียนก่อนหน้า คุณทราบดีว่า หากกำหนดตัวแปร ใดๆ ในฟังก์ชันภายนอก มันจะ สามารถเข้าถึงได้ในฟังก์ชันภายใน:

javascriptfunction parent() {
  let str = 'abcde';
  
  function child() {
    console.log(str); // จะแสดง 'abcde'
  }
  child(); // เรียกใช้ฟังก์ชันภายใน
}

parent(); // เรียกใช้ฟังก์ชันภายนอก

อย่างไรก็ตาม มีข้อปลีกย่อย: ฟังก์ชันภายในสามารถ เข้าถึงตัวแปรทั้งหมดของฟังก์ชันภายนอกได้ แต่ไม่สามารถ เข้าถึง this ได้ นั่นคือ: หาก ฟังก์ชันภายนอกถูกผูกกับ element DOM ตัวใดตัวหนึ่ง แล้ว this ในฟังก์ชันนั้นจะชี้ไปที่ element นั้น แต่ this ของฟังก์ชัน ภายในจะไม่ชี้!

แล้ว this ของฟังก์ชันภายในจะชี้ไปที่อะไรล่ะ? คำตอบ: มันจะเท่ากับ undefined (ในโหมด strict) เนื่องจาก ฟังก์ชันไม่ได้ถูกผูกกับอะไรเลย

ลองทดสอบในทางปฏิบัติ สมมติว่าเรามี input:

html<input id="elem" value="text">

ลองผูกฟังก์ชัน parent กับ input นี้ ซึ่งจะถูกเรียกเมื่อ input สูญเสียโฟกัส:

javascript"use strict";

let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);

// จะถูกเรียกเมื่อสูญเสียโฟกัส:
function parent() {
  // จะมีโค้ดบางอย่างตรงนี้
  
  function child() {
    // จะมีโค้ดบางอย่างตรงนี้
  }
  child(); // เรียกฟังก์ชันลูก
}

ลองแสดงเนื้อหาของ this ไปยัง console ในสองตำแหน่ง: ภายในฟังก์ชัน parent และภายในฟังก์ชัน child:

javascript"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 ชี้ไปไม่ถูกต้องตามที่เราต้องการ อย่างไม่คาดคิด เรียกว่า การสูญเสียบริบท

Задание 1

สมมติว่าตอนนี้ทั้งในฟังก์ชันแรกและฟังก์ชันที่สอง เราจะแสดง value ของ input ลองกำหนดดูว่า อะไรจะถูกแสดงในบรรทัดของโค้ดที่ทำเครื่องหมายด้วย ความคิดเห็น:

javascript"use strict";

let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);

function parent() {
  console.log(this.value); // จะแสดงอะไร?
  
  function child() {
    console.log(this.value); // จะแสดงอะไร?
  }
  child();
}