Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Javascript

ความรู้พื้นฐานเกี่ยวกับเว็บ:การปิดขอบเขตและ JavaScript – a Primer

หนึ่งในคำศัพท์ที่ใหญ่ที่สุดในภาษา JavaScript คือการปิด เป็นเรื่องของคำถามสัมภาษณ์งานที่บริษัท FAANG มากมาย ในบทความนี้ เราจะพูดถึงการปิดและขอบเขต แสดงแนวคิดด้วยตัวอย่างง่ายๆ แล้วปิดท้ายด้วยคำถามตัวอย่างจากการสัมภาษณ์หนึ่งในยักษ์ใหญ่ด้านเทคโนโลยีที่ใหญ่กว่า

ขอบเขต

เมื่อมีคนบอกคุณว่ามีบางอย่างอยู่ในขอบเขตของโครงการหรือไม่ นั่นหมายความว่าอย่างไร

ฉันต้องการนึกถึงกล้องปริทรรศน์หรือกล้องโทรทรรศน์เมื่อคิดถึงคำตอบนี้ เครื่องมือเหล่านี้แสดงให้เราเห็นทุกสิ่งภายในขอบเขตของเลนส์ที่มีอยู่:อยู่ในขอบเขต . หากอยู่นอกขอบเขต คุณไม่สามารถมองผ่านเส้นผ่านศูนย์กลางของเลนส์ได้ และไม่สามารถฉายแสงบนวัตถุที่อยู่นอกเส้นผ่านศูนย์กลางได้ คุณควรคิดถึงเรื่องนี้ในขณะที่เราพูดถึงขอบเขตที่สำคัญและแตกต่างกันสามประเภทใน JavaScript:โลคัล โกลบอล และศัพท์

ขอบเขตท้องถิ่น

ขอบเขตท้องถิ่นคือขอบเขตที่เล็กที่สุดในสามขอบเขตที่เราจะพูดถึงในวันนี้ เมื่อเราประกาศฟังก์ชัน สิ่งใดก็ตามในวงเล็บ ({}) จะถือว่าเป็นฟังก์ชันภายในเครื่อง เมื่อเอ็นจิ้น JavaScript อ่านฟังก์ชัน จะประกาศตัวแปร เมื่อมันจบลง มันจะทำลายตัวแปร

function greeting() {
 var websiteName = 'Career Karma';
 return `Hello ${websiteName}`;
}
 
console.log(greeting()); // Hello Career Karma
console.log(websiteName); // ReferenceError: websiteName is not defined

อย่างที่คุณเห็น เมื่อเรา "console.log()" ผลลัพธ์ของฟังก์ชันทักทายที่เรียก เราสามารถเข้าถึงชื่อเว็บไซต์ได้หลังจากดำเนินการฟังก์ชันแล้ว สิ่งนี้ทำให้เรามีสตริง 'Hello Career Karma' ที่เรากำลังมองหา console.log() ของตัวแปรที่ถูกประกาศภายในฟังก์ชันทำให้เกิดข้อผิดพลาดเนื่องจากไม่ได้กำหนดไว้

ดังที่กล่าวไปแล้ว สาเหตุที่ชื่อเว็บไซต์ไม่ได้กำหนดไว้นั้นเป็นเพราะว่าตัวแปรถูกสร้างขึ้นภายในฟังก์ชันเมื่อมีการเรียกใช้งานและถูกทำลายเมื่อคำสั่งเทอร์มินัลทำงาน สิ่งใดก็ตามที่อยู่นอกฟังก์ชันจะไม่สามารถเข้าถึงสิ่งต่างๆ ภายในฟังก์ชันได้ เว้นแต่จะมีการตั้งค่าพิเศษ

ขอบเขตสากล

ขอบเขตถัดไปนี้เป็นการแปลตามตัวอักษรของวลี ขอบเขตสากลนำรายการที่ประกาศไว้นอกฟังก์ชันและสำรองไว้ในพื้นที่ที่สคริปต์และเมธอดและฟังก์ชันทั้งหมดสามารถเข้าถึงและใช้สำหรับตรรกะ

 
let counter = 0; // global -- declared outside function
 
const add = () => { // function declaration
   let counter = 0; // local -- declared inside function
   counter += 1; 
   // counter increased by 1 -- which counter variable increased?
   return counter;
}
 
add(); // invoke
add(); //  three
add(); //  times
console.log(counter) // is this 3 or 0? Why? 

โค้ดด้านบนทำอะไรถ้าเรา console.log() เคาน์เตอร์ท้ายโค้ด? คุณคาดหวังว่าจะเกิดอะไรขึ้น?

81% ของผู้เข้าร่วมกล่าวว่าพวกเขารู้สึกมั่นใจมากขึ้นเกี่ยวกับโอกาสในการทำงานด้านเทคโนโลยีหลังจากเข้าร่วม bootcamp จับคู่กับ Bootcamp วันนี้

ผู้สำเร็จการศึกษาจากหลักสูตร bootcamp โดยเฉลี่ยใช้เวลาน้อยกว่าหกเดือนในการเปลี่ยนอาชีพ ตั้งแต่เริ่มต้น bootcamp ไปจนถึงหางานแรก

มาดูรหัสกัน:

  1. ตัวแปรตัวนับที่ประกาศและเริ่มต้นในสภาพแวดล้อมส่วนกลาง
  2. เพิ่มฟังก์ชันที่ประกาศในสภาพแวดล้อมส่วนกลาง
  3. เรียกเพิ่ม
  4. ตัวแปรตัวนับที่ประกาศและเริ่มต้นในสภาพแวดล้อมท้องถิ่น
  5. ตัวนับในพื้นที่เพิ่มขึ้น 1 ⇐ ทำไมในเครื่องถึงไม่ใช่ทั่วโลก?
  6. เคาน์เตอร์ถูกส่งกลับ ฟังก์ชันสิ้นสุดลง
  7. เรียกเพิ่มอีกครั้ง
  8. ทำตามขั้นตอนที่ 4 ถึง 6 อีกครั้ง
  9. ทำซ้ำขั้นตอนที่ 3 ถึง 6 อีกครั้ง
  10. console.log(counter); ⇐ ได้อะไรกลับมาบ้าง?

เนื่องจากฟังก์ชันจะสิ้นสุดเมื่อตัวนับอยู่ที่ 1 ทุกครั้ง ตัวแปรตัวนับในพื้นที่ของเราจึงถูกประกาศใหม่และเริ่มต้นใหม่เป็น 0 ทุกครั้งที่ฟังก์ชันทำงาน ไม่ว่าจะเกิดอะไรขึ้น เคาน์เตอร์จะหยุดที่ 1 ในระดับท้องถิ่นเสมอ

หากฟังก์ชันพบตัวแปรภายในขอบเขต ฟังก์ชันจะไม่มองไปที่ขอบเขตส่วนกลางของตัวแปร ดังนั้นตัวแปรส่วนกลางจะไม่เปลี่ยนแปลง ดังนั้น console.log() . ของเรา จะส่งออก 0 เนื่องจากตัวแปรที่กำหนดไว้ที่ใกล้เคียงที่สุดของเราภายในสภาพแวดล้อมของคำสั่งนั้นอยู่ในสภาพแวดล้อมส่วนกลาง

ขอบเขตคำศัพท์

ขอบเขตคำศัพท์เป็นหนึ่งในแนวคิดพื้นฐานที่สุดใน JavaScript เป็นแนวคิดที่ว่าการสร้างฟังก์ชันหรือตัวแปรจะสามารถเข้าถึงได้ในบางส่วนของโค้ด และจากนั้นจะไม่สามารถเข้าถึงส่วนอื่นๆ ของโค้ดได้ ทุกอย่างขึ้นอยู่กับการประกาศของตัวแปรและฟังก์ชันแต่ละตัว

ลองดูที่บล็อกของรหัสนี้:

const init = () => { // <== This is our outer function
 const var1 = 'Career'; // outer scope
 const second = () => { // <== This is our inner function
   const var2 = 'Karma'; // inner scope
   console.log(var1); // Career
   console.log(var2); // Karma
   return var1 + " " + var2;
 };
 
 // console.log(var2); // undefined
 
 
 return second();
};
init();
 

ที่นี่เรามีชุดของฟังก์ชันที่ซ้อนกัน init() ฟังก์ชั่นประกาศตัวแปรที่เรียกว่า var1 ประกาศฟังก์ชั่นที่เรียกว่าวินาทีและเรียกใช้ second() .

เมื่อคอมไพเลอร์ส่งผ่านโค้ดนี้ในครั้งแรก จะพิจารณาอย่างสูงว่าเรามีอะไรบ้าง:

  1. init() ฟังก์ชัน
  2. เรียกใช้ init()

ณ จุดนี้ เราไม่เห็นสิ่งอื่นใดในฟังก์ชัน init() เราเพิ่งรู้ว่ามีฟังก์ชันนี้อยู่ เมื่อเรียกใช้ init() func ของเรา คอมไพเลอร์จะพิจารณาระดับสูงอีกครั้งว่ามีอะไรอยู่ในฟังก์ชัน:

  1. var1
  2. second() ฟังก์ชัน
  3. เรียกใช้ second()

init() ฟังก์ชั่นไม่รู้อะไรเลยเกี่ยวกับสิ่งที่เกิดขึ้นภายใน second() บล็อก. มองเห็นได้เฉพาะสิ่งที่อยู่ในสภาพแวดล้อมของคำศัพท์ – สภาพโดยรอบ

แต่ละฟังก์ชันที่ซ้อนกันอยู่ในภาชนะขนาดเล็ก เช่น ชุดตุ๊กตาแม่ลูกดกของรัสเซีย (ดูด้านบนสุดของหน้า เช่น หากคุณไม่แน่ใจว่ามันคืออะไร) ตุ๊กตาเท่านั้นที่รู้เกี่ยวกับสิ่งที่เกิดขึ้นภายในภาชนะและสิ่งที่เกิดขึ้นแล้วหรือประกาศ/อ่านในผู้ปกครอง ตัวอย่างเช่น ตุ๊กตาที่ใหญ่ที่สุดรู้เพียงว่าตุ๊กตาตัวต่อไปในภาชนะนั้นมีอยู่จริง มันไม่รู้เกี่ยวกับตุ๊กตาตัวอื่นๆ ในชุด ว่ามีอะไรอยู่ในสภาพแวดล้อมของคำศัพท์ (สถานะของมัน) และสิ่งที่เกิดขึ้นแล้ว (ขอบเขตภายนอก)

โดยพื้นฐานแล้ว เรารู้สองสิ่ง:

  1. ขอบเขตภายนอกมองไม่เห็นขอบเขตภายใน
  2. ขอบเขตภายในสามารถเข้าถึงขอบเขตภายนอกได้

เนื่องจากการรับมือภายนอกไม่สามารถมองเห็นสิ่งที่เกิดขึ้นภายในขอบเขต เราสามารถพูดได้อย่างปลอดภัยว่านี่เป็นความสัมพันธ์แบบทางเดียว ภายในมองเห็นและใช้ตัวแปรจากขอบเขตภายนอกได้ แต่ภายนอกจะมองไม่เห็นภายใน สิ่งนี้เรียกว่า ขอบเขตคำศัพท์ .

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

สิ่งนี้กลายเป็นแนวคิดที่สำคัญมากใน JavaScript ที่จะเกิดขึ้นครั้งแล้วครั้งเล่าเมื่อคุณเรียนรู้เพิ่มเติมเกี่ยวกับเฟรมเวิร์ก JavaScript และวิธีการทำงาน คุณสามารถผ่านลงมาจากด้านนอกได้ แต่คุณไม่สามารถผ่าน "ขึ้น" ไปอีกทางหนึ่งได้ สิ่งนี้สำคัญมากเมื่อเราไปถึงหัวข้อหลัก:ปิด .

ปิด

คำจำกัดความของการปิดนั้นคล้ายกับขอบเขตคำศัพท์มาก ข้อแตกต่างที่สำคัญระหว่างทั้งสองคือ การปิดเป็นฟังก์ชันลำดับที่สูงกว่า และการกำหนดขอบเขตคำศัพท์ไม่ใช่ ฟังก์ชันลำดับที่สูงกว่ามีลักษณะพื้นฐานหนึ่งอย่าง:จะคืนค่าฟังก์ชันหรือใช้ฟังก์ชันเป็นพารามิเตอร์

การปิดเป็นฟังก์ชันที่สามารถเข้าถึงขอบเขตคำศัพท์ได้ แม้ว่าฟังก์ชันนั้นจะถูกเรียกใช้ในภายหลัง

ทั้งขอบเขตการปิดและคำศัพท์มีตัวแปรของตัวเอง สามารถเข้าถึงตัวแปรและพารามิเตอร์ของฟังก์ชันหลัก และสามารถใช้ตัวแปรส่วนกลางได้ มาดูรหัสต่อไปนี้กัน:

function greeting() { //outer scope (parent function)
 const userName = "CrrKrma1952"; // parent variable
 function welcomeGreeting() { // inner function
   console.log("Hello, " + userName); // accesses parent var
   return "Hello, " + userName; // terminal statement
 }
 return welcomeGreeting; // returns a function (which makes it HOF)
} // end of greeting()
 
const greetUser = greeting(); //
greetUser(); //  Hello, CrrKrma1952
  1. greeting() มีฟังก์ชันอยู่แต่เรายังไม่ทราบเนื้อหา
  2. greetUser มีอยู่แต่ยังไม่รู้เนื้อหา
  3. greetUser() – เรียกใช้บรรทัดก่อนหน้า ซึ่งในทางกลับกัน จะเรียกใช้ฟังก์ชัน greeting()
  4. ชื่อผู้ใช้ถูกประกาศ
  5. welcomeGreeting() มีอยู่แต่ยังไม่รู้เนื้อหา
  6. ส่งคืนคำสั่งด้านล่าง welcomeGreeting() block ส่งคืนฟังก์ชันเดียวกันนั้นมาก
  7. console.log(‘Hello, ‘ + userName); console.log ของเราที่นี่สามารถเข้าถึงขอบเขตหลักเพื่อรับค่าของชื่อผู้ใช้
  8. คำสั่งเทอร์มินัลที่สิ้นสุดฟังก์ชันและทำลายความหมายของตัวแปรภายในบล็อคโค้ด

ในโค้ดนี้ เรากำลังส่งข้อมูลโดยการซ้อนฟังก์ชันเข้าด้วยกัน เพื่อให้สามารถเข้าถึงขอบเขตหลักได้ในภายหลัง



บทสรุป

ในบทความนี้ เราได้พูดถึงหัวข้อ JavaScript ที่ค่อนข้างแข็งแกร่ง:ขอบเขตและการปิด ฉันอยากจะแนะนำให้แยกย่อยและอ่านบทความต่าง ๆ เกี่ยวกับเรื่องนี้ วิธีการสอนนี้สามารถมาจากมุมมองที่หลากหลาย ซึ่งหมายความว่ามีวิธีมากมายในการเรียนรู้ ฉันหวังว่าไพรเมอร์นี้จะเป็นประโยชน์กับคุณ! ขอให้โชคดีในการศึกษาต่อเกี่ยวกับการปิดทำการ!