การปิดเป็นคุณสมบัติที่สำคัญใน JavaScript และฟังก์ชั่นที่ใหญ่ที่สุดของพวกเขาคือการบันทึกข้อมูลระหว่างการทำงานของฟังก์ชั่น ใน JavaScript คุณสมบัติการปิดจำนวนมากได้มาจากห่วงโซ่ขอบเขตในระหว่างการเรียกใช้ฟังก์ชัน
ห่วงโซ่ขอบเขตของฟังก์ชั่นการเรียกวัตถุและตัวแปร
สำหรับการเรียกใช้ฟังก์ชั่นแต่ละรายการใน JavaScript JavaScript จะสร้างวัตถุท้องถิ่นเพื่อจัดเก็บตัวแปรท้องถิ่นที่กำหนดไว้ในฟังก์ชั่น หากมีฟังก์ชั่นซ้อนอยู่ภายในฟังก์ชั่น JavaScript จะกำหนดวัตถุท้องถิ่นที่ซ้อนกันในวัตถุท้องถิ่นที่กำหนดไว้แล้ว สำหรับฟังก์ชั่นมีคำจำกัดความฟังก์ชั่นซ้อนกันหลายชั้นเช่นเดียวกับที่มีหลายชั้นของวัตถุท้องถิ่นที่ซ้อนกันเช่นเดียวกับที่มี วัตถุท้องถิ่นนี้เรียกว่า "ฟังก์ชั่นการเรียกวัตถุ" ("วัตถุเรียก" ใน eCmascript 3 และถูกเปลี่ยนชื่อ "บันทึกสภาพแวดล้อมที่ประกาศ" ใน ECMAScript 5 แต่โดยส่วนตัวฉันคิดว่าชื่อใน ECMASCRIPT 3 นั้นง่ายต่อการเข้าใจ) การเรียกใช้ฟังก์ชันต่อไปนี้ใช้เป็นตัวอย่าง:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น f (x) {
var a = 10;
ส่งคืน a*x;
-
console.log (f (6)); // 60
ในตัวอย่างง่ายๆนี้เมื่อเรียกใช้ฟังก์ชัน F () JavaScript จะสร้างวัตถุการโทรของฟังก์ชัน f () (เรียกมันว่า f_invokeobj) มีสองคุณสมบัติภายในวัตถุ f_invokeobj: a และ x; เมื่อ F () ทำงานค่า A คือ 10 และค่า x คือ 6 ดังนั้นผลลัพธ์การส่งคืนสุดท้ายคือ 60 ภาพประกอบมีดังนี้:
เมื่อมีการทำรังฟังก์ชั่น JavaScript จะสร้างวัตถุการเรียกใช้ฟังก์ชันหลายรายการ:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น f (x) {
var a = 10;
ส่งคืน a*g (x);
ฟังก์ชั่น g (b) {
กลับ b*b;
-
-
console.log (f (6)); // 360
ในตัวอย่างนี้เมื่อเรียกใช้ฟังก์ชัน F () JavaScript จะสร้างวัตถุการโทรของฟังก์ชัน F () (F_INVOKEOBJ) ซึ่งมีสองแอตทริบิวต์ A และ X และค่า A คือ 10 และค่า x คือ 6; เมื่อเรียกใช้ f () JavaScript จะแยกวิเคราะห์และกำหนดฟังก์ชัน g () ในฟังก์ชัน f () และสร้างวัตถุการโทรของ g () (g_invokeobj) ซึ่งมีแอตทริบิวต์ B และค่า B เหมือนกับพารามิเตอร์ที่ผ่าน X ดังนั้นผลลัพธ์การส่งคืนสุดท้ายคือ 360 ภาพประกอบดังนี้
อย่างที่คุณเห็นวัตถุการเรียกใช้ฟังก์ชันเป็นโซ่ เมื่อฟังก์ชั่นฝังตัว g () กำลังทำงานอยู่และจำเป็นต้องได้รับค่าตัวแปรมันจะเริ่มค้นหาจากวัตถุเรียกใช้ฟังก์ชันล่าสุด หากไม่สามารถค้นหาได้การค้นหาในวัตถุการโทรเพิ่มเติมตามห่วงโซ่วัตถุเรียกใช้ฟังก์ชันซึ่งเรียกว่า "โซ่ขอบเขตของตัวแปร" หากตัวแปรเดียวกันปรากฏในวัตถุเรียกใช้ฟังก์ชันสองฟังก์ชันฟังก์ชั่นจะใช้ค่าตัวแปรในวัตถุการโทรที่ใกล้เคียงที่สุด:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น f (x) {
var a = 10;
ส่งคืน a*g (x);
ฟังก์ชั่น g (b) {
var a = 1;
กลับ b*b*a;
-
-
console.log (f (6)); // 360, ไม่ใช่ 3600
ในตัวอย่างข้างต้นตัวแปร A มีค่าที่แตกต่างกันในวัตถุการเรียก (g_invokeobj) ของฟังก์ชัน g () และวัตถุที่เรียก (f_invokeobj) ของฟังก์ชัน f () เมื่อเรียกใช้ฟังก์ชั่น g () ค่าของฟังก์ชันที่ใช้ภายในฟังก์ชัน g () คือ 1 ในขณะที่ค่าของการใช้นอกฟังก์ชัน g () คือ 1. ฟังก์ชันการเรียกใช้โซ่วัตถุในเวลานี้มีดังนี้:
การปิดคืออะไร?
ฟังก์ชั่นทั้งหมดในจาวาสคริปต์เป็นวัตถุและเมื่อกำหนดฟังก์ชั่นจะมีการสร้างสายโซ่ที่สอดคล้องกันของฟังก์ชั่นการเรียกวัตถุ คำจำกัดความของฟังก์ชั่นสอดคล้องกับห่วงโซ่ของฟังก์ชั่นการเรียกวัตถุ ตราบใดที่วัตถุฟังก์ชั่นมีอยู่วัตถุเรียกใช้ฟังก์ชันที่สอดคล้องกันมีอยู่; เมื่อไม่ได้ใช้ฟังก์ชั่นอีกต่อไปวัตถุเรียกใช้ฟังก์ชั่นที่สอดคล้องกันจะถูกเก็บรวบรวมขยะ และการรวมกันของวัตถุฟังก์ชั่นและห่วงโซ่ของวัตถุเรียกใช้ฟังก์ชันเรียกว่า "การปิด" ในตัวอย่างด้านบนของฟังก์ชัน f () และฟังก์ชัน g () มีการปิดสองครั้ง: วัตถุฟังก์ชัน F () และวัตถุ F_INVOKEOBJ จะปิดการปิดและวัตถุฟังก์ชัน G () และ G_INVOKEOBJ-F_INVOKEOBJ เมื่อฟังก์ชั่น g () ถูกดำเนินการเนื่องจากฟังก์ชั่น g () ไม่ได้ใช้อีกต่อไปการปิด G () จะถูกเก็บรวบรวมขยะ; จากนั้นเมื่อฟังก์ชั่น F () ถูกดำเนินการการปิด F () จะถูกเก็บรวบรวมด้วยเหตุผลเดียวกัน
จากคำจำกัดความของการปิดเราสามารถสรุปได้: ฟังก์ชั่น JavaScript ทั้งหมดจะปิดหลังจากคำจำกัดความเนื่องจากฟังก์ชั่นทั้งหมดเป็นวัตถุและฟังก์ชั่นทั้งหมดยังมีโซ่วัตถุโทรที่สอดคล้องกันหลังจากดำเนินการ
อย่างไรก็ตามสิ่งที่ทำให้การปิดใช้งานได้จริงคือกรณีของฟังก์ชั่นซ้อน เนื่องจากฟังก์ชั่นฝังตัวถูกกำหนดเฉพาะเมื่อฟังก์ชั่นภายนอกทำงานค่าตัวแปรที่เก็บไว้ในการปิดฟังก์ชั่นฝังตัว (โดยเฉพาะค่าตัวแปรท้องถิ่นของฟังก์ชันภายนอก) เป็นค่าระหว่างการรันนี้ ตราบใดที่วัตถุฟังก์ชันฝังตัวยังคงมีอยู่การปิดของมันยังคงมีอยู่ (ค่าตัวแปรในการปิดจะไม่เปลี่ยนแปลงใด ๆ ) ดังนั้นจึงบรรลุวัตถุประสงค์ในการบันทึกข้อมูลของกระบวนการทำงาน พิจารณาตัวอย่างต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var a = "ภายนอก";
ฟังก์ชั่น f () {
var a = "ภายใน";
ฟังก์ชัน g () {return a;}
กลับ G;
-
var result = f ();
console.log (result ()); // ภายใน
ในตัวอย่างนี้เมื่อฟังก์ชั่น F () ทำงานฟังก์ชั่น G () จะถูกกำหนดและการปิดฟังก์ชั่น G () จะถูกสร้างขึ้น การปิด G () ประกอบด้วยห่วงโซ่วัตถุ G_INVOKEOBJ-F_INVOKEOBJ ดังนั้นค่าตัวแปร A ในระหว่างการดำเนินการฟังก์ชัน F () จะถูกบันทึกไว้ เมื่อคำสั่ง console.log () ถูกดำเนินการการปิด G () ยังคงมีอยู่เนื่องจากวัตถุฟังก์ชัน G ยังคงมีอยู่; เมื่อเรียกใช้วัตถุฟังก์ชัน G ที่ยังมีอยู่นี้ JavaScript จะใช้การปิด G () ที่ยังมีอยู่และรับค่าของตัวแปร A ("ภายใน") จากมัน