var foo = "hello"; var c = (ฟังก์ชั่น a () {function b () {var bar = "world"; การแจ้งเตือน (foo + bar); return bar;} return b;}) () (); แจ้งเตือน (foo + c);ตัวอย่างนี้ปรากฏขึ้น Hello World สองครั้ง
1. การปิดคืออะไร?
คำอธิบาย "อย่างเป็นทางการ" คือ: สิ่งที่เรียกว่า "ปิด" หมายถึงนิพจน์ (โดยปกติจะเป็นฟังก์ชั่น) ที่มีตัวแปรมากมายและสภาพแวดล้อมที่ผูกพันกับตัวแปรเหล่านี้ดังนั้นตัวแปรเหล่านี้จึงเป็นส่วนหนึ่งของการแสดงออก
ฉันเชื่อว่ามีคนไม่กี่คนที่สามารถเข้าใจประโยคนี้ได้โดยตรงเพราะเขาอธิบายว่ามันเป็นเรื่องเชิงวิชาการมากเกินไป ฉันต้องการใช้วิธีการสร้างการปิดใน JavaScript เพื่อบอกคุณว่าการปิดคืออะไรเพราะมันยากมากที่จะเข้าใจคำจำกัดความของการปิดโดยตรงโดยการข้ามกระบวนการสร้างปิด ดูรหัสต่อไปนี้:
ฟังก์ชั่น a () {var i = 0; ฟังก์ชัน b () {แจ้งเตือน (++ i);} return b;} var c = a (); c ();รหัสนี้มีสองลักษณะ:
1. ฟังก์ชั่น B ซ้อนอยู่ภายในฟังก์ชั่น A;
2. ฟังก์ชั่น A การส่งคืนฟังก์ชัน b.
ด้วยวิธีนี้หลังจากดำเนินการ var c = a () ตัวแปร C จะชี้ไปที่ฟังก์ชัน b หลังจากดำเนินการ c () หน้าต่างจะปรากฏขึ้นเพื่อแสดงค่าของ i (ครั้งแรกคือ 1) รหัสนี้สร้างการปิดจริง ทำไม เนื่องจากตัวแปร C ภายนอกฟังก์ชั่น A หมายถึงฟังก์ชั่น B ภายในฟังก์ชั่น A นั่นคือ,:
เมื่อฟังก์ชั่นภายใน B ของฟังก์ชั่น A ถูกอ้างอิงโดยตัวแปรภายนอกฟังก์ชั่น A การปิดจะถูกสร้างขึ้น
ฉันเดาว่าคุณยังไม่เข้าใจการปิดเพราะคุณไม่รู้ว่ามีการปิดอะไรบ้าง มาสำรวจด้านล่าง
2. ฟังก์ชั่นของการปิดคืออะไร?
ในระยะสั้นฟังก์ชั่นของการปิดคือหลังจากที่ A ถูกดำเนินการและส่งคืนการปิดทำให้กลไกการรวบรวมขยะ JavaScript GC ไม่กู้คืนทรัพยากรที่ถูกครอบครองโดย A เนื่องจากการดำเนินการของฟังก์ชั่นภายใน B ของความต้องการที่จะพึ่งพาตัวแปรใน นี่เป็นคำอธิบายที่ตรงไปตรงมามากเกี่ยวกับบทบาทของการปิดซึ่งไม่ได้เป็นมืออาชีพหรือเข้มงวด แต่ก็หมายความว่ามันเป็น การทำความเข้าใจการปิดจำเป็นต้องมีกระบวนการค่อยเป็นค่อยไป
ในตัวอย่างข้างต้นหลังจากที่ฟังก์ชั่น A ถูกส่งคืนฉันอยู่ในนั้นอยู่เสมอดังนั้นทุกครั้งที่ C () จะถูกดำเนินการฉันเป็นค่าของฉันแจ้งเตือนหลังจากเพิ่ม 1
แล้วลองจินตนาการถึงสถานการณ์อื่น หากผลตอบแทนไม่ทำงาน B สถานการณ์จะแตกต่างกันอย่างสิ้นเชิง เพราะหลังจากถูกประหารชีวิต B จะไม่ถูกส่งกลับไปยังโลกภายนอกของ A แต่มีการอ้างอิงโดย A และในเวลานี้ A จะถูกอ้างอิงโดย B เท่านั้นดังนั้นฟังก์ชั่น A และ B จะถูกอ้างอิงซึ่งกันและกัน แต่ไม่ถูกรบกวนจากโลกภายนอก (กลไกการรวบรวมขยะของ JavaScript จะถูกนำเสนอในรายละเอียดในภายหลัง)
3. โลกกล้องจุลทรรศน์ในการปิด
หากเราต้องการมีความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับความสัมพันธ์ระหว่างการปิดและฟังก์ชั่น A และฟังก์ชั่นที่ซ้อนกัน B เราจำเป็นต้องแนะนำแนวคิดอื่น ๆ อีกมากมาย: สภาพแวดล้อมการดำเนินการของฟังก์ชั่น (บริบทการกระตุ้น) วัตถุที่ใช้งานอยู่ (วัตถุเรียก) ขอบเขต (ขอบเขต) และโซ่ขอบเขต ใช้กระบวนการของฟังก์ชั่น A จากคำจำกัดความไปสู่การดำเนินการเป็นตัวอย่างเพื่อแสดงแนวคิดเหล่านี้
1. เมื่อกำหนดฟังก์ชั่น A, JS Interpreter จะตั้งค่าขอบเขตห่วงโซ่ของฟังก์ชั่น A เป็น "สภาพแวดล้อม" ที่ A ตั้งอยู่เมื่อกำหนด หาก A เป็นฟังก์ชั่นทั่วโลกมีเพียงวัตถุหน้าต่างในห่วงโซ่ขอบเขต
2. เมื่อฟังก์ชั่น A ถูกดำเนินการ A จะป้อนสภาพแวดล้อมการดำเนินการที่สอดคล้องกัน (บริบทการกระตุ้น)
3. ในกระบวนการสร้างสภาพแวดล้อมการดำเนินการจะเพิ่มแอตทริบิวต์ขอบเขตก่อนนั่นคือขอบเขตของ A และค่าของมันคือห่วงโซ่ขอบเขตในขั้นตอนที่ 1 นั่นคือห่วงโซ่ขอบเขตของ A.Scope = A
4. สภาพแวดล้อมการดำเนินการจะสร้างวัตถุที่ใช้งานอยู่ (วัตถุโทร) วัตถุที่ใช้งานยังเป็นวัตถุที่มีแอตทริบิวต์ แต่ไม่มีต้นแบบและไม่สามารถเข้าถึงได้โดยตรงผ่านรหัส JavaScript หลังจากสร้างวัตถุที่ใช้งานอยู่ให้เพิ่มวัตถุที่ใช้งานอยู่ที่ด้านบนของห่วงโซ่ขอบเขตของ A ในเวลานี้ห่วงโซ่ขอบเขตของ A มีวัตถุสองชิ้น: วัตถุที่ใช้งานอยู่ของ A และวัตถุหน้าต่าง
5. ขั้นตอนต่อไปคือการเพิ่มแอตทริบิวต์อาร์กิวเมนต์ลงในวัตถุที่ใช้งานอยู่ซึ่งจะบันทึกพารามิเตอร์ที่ส่งผ่านเมื่อฟังก์ชั่นการโทร
6. ในที่สุดเพิ่มพารามิเตอร์ที่เป็นทางการทั้งหมดของฟังก์ชัน A และการอ้างอิงไปยังฟังก์ชั่นภายใน B ลงในวัตถุที่ใช้งานอยู่ของ A ในขั้นตอนนี้คำจำกัดความของฟังก์ชั่น B เสร็จสมบูรณ์ดังนั้นในขั้นตอนที่ 3 ขอบเขตของห่วงโซ่ของฟังก์ชั่น B ถูกตั้งค่าเป็นสภาพแวดล้อมที่กำหนดโดย B นั่นคือขอบเขตของ A
ณ จุดนี้ฟังก์ชั่นทั้งหมด A เสร็จสมบูรณ์จากคำจำกัดความถึงการดำเนินการ ในเวลานี้จะส่งคืนการอ้างอิงไปยังฟังก์ชัน B ถึง C และขอบเขตห่วงโซ่ของฟังก์ชั่น B มีการอ้างอิงไปยังวัตถุที่ใช้งานอยู่ของฟังก์ชั่น A นั่นคือ B สามารถเข้าถึงตัวแปรและฟังก์ชั่นทั้งหมดที่กำหนดไว้ใน A ฟังก์ชั่น B ถูกอ้างอิงโดย C และฟังก์ชั่น B ขึ้นอยู่กับฟังก์ชั่น A ดังนั้นฟังก์ชัน A จะไม่ถูกรีไซเคิลโดย GC หลังจากส่งคืน
เมื่อฟังก์ชั่น B ถูกดำเนินการมันก็จะเหมือนกับข้างต้น ดังนั้นห่วงโซ่ขอบเขตของ B ในระหว่างการดำเนินการมีวัตถุ 3 ชิ้น: วัตถุที่ใช้งานอยู่ของ B, วัตถุที่ใช้งานอยู่ของ A และวัตถุหน้าต่างดังแสดงในรูปด้านล่าง:
ดังที่แสดงในรูปเมื่อเข้าถึงตัวแปรในฟังก์ชั่น B ลำดับการค้นหาคือการค้นหาวัตถุที่ใช้งานของตัวเองเป็นอันดับแรกและหากมีอยู่มันจะกลับมา หากไม่มีอยู่มันจะยังคงค้นหาวัตถุที่ใช้งานอยู่ของฟังก์ชั่น A และค้นหาในทางกลับกันจนกว่าจะพบ หากไม่สามารถพบได้ในห่วงโซ่ขอบเขตทั้งหมดที่ไม่ได้กำหนดจะถูกส่งคืน หากมีวัตถุต้นแบบต้นแบบสำหรับฟังก์ชั่น B จากนั้นหลังจากค้นหาวัตถุที่ใช้งานของตัวเองก่อนอื่นให้ค้นหาวัตถุต้นแบบของตัวเองแล้วค้นหาต่อไป นี่คือกลไกการค้นหาตัวแปรใน JavaScript
4. สถานการณ์แอปพลิเคชันของการปิด
1. ปกป้องความปลอดภัยของตัวแปรในฟังก์ชัน จากตัวอย่างแรกเป็นตัวอย่างในฟังก์ชั่น A ฉันสามารถเข้าถึงได้โดยฟังก์ชั่น B เท่านั้น แต่ไม่สามารถเข้าถึงได้ผ่านช่องทางอื่น ๆ ดังนั้นจึงปกป้องความปลอดภัยของ I
2. รักษาตัวแปรในหน่วยความจำ ยังคงเหมือนก่อนหน้านี้เนื่องจากการปิดฉันทำงานอยู่ในหน่วยความจำเสมอดังนั้นทุกครั้งที่ C () จะถูกดำเนินการฉันจะถูกเพิ่ม 1
สองจุดข้างต้นเป็นสถานการณ์แอปพลิเคชันขั้นพื้นฐานที่สุดสำหรับการปิดและกรณีคลาสสิกจำนวนมากมาจากสิ่งนี้
5. กลไกการรวบรวมขยะของ JavaScript
ใน JavaScript หากวัตถุไม่ได้อ้างอิงอีกต่อไปวัตถุจะถูกนำกลับมาใช้ใหม่โดย GC หากมีการอ้างอิงวัตถุสองชิ้นซึ่งกันและกันและไม่ได้อ้างอิงจากบุคคลที่สามอีกต่อไปวัตถุทั้งสองที่อ้างอิงซึ่งกันและกันจะถูกนำกลับมาใช้ใหม่ เนื่องจากฟังก์ชั่น A ถูกอ้างอิงโดย B, B ถูกอ้างอิงโดย C นอก A ซึ่งเป็นสาเหตุที่ฟังก์ชัน A จะไม่ถูกรีไซเคิลหลังจากดำเนินการ
บทความข้างต้นเข้าใจกลไกการปิดอย่างครอบคลุมคือเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่าคุณจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น