ขยายเพิ่มเติมในคำตอบก่อนหน้า ...
จากมุมมองของคอมไพเลอร์ทั่วไปและไม่คำนึงถึงการปรับให้เหมาะสมเฉพาะกับ VM:
อันดับแรกเราต้องผ่านขั้นตอนการวิเคราะห์คำซึ่งเราทำเครื่องหมายโค้ด
โดยวิธีตัวอย่างโทเค็นต่อไปนี้อาจถูกสร้าง:
[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)
หวังว่าสิ่งนี้จะช่วยให้คุณมีการสร้างภาพข้อมูลที่เพียงพอเพื่อให้คุณสามารถเข้าใจว่าต้องมีการประมวลผลมากขึ้น (หรือน้อยลง)
จากโทเค็นข้างต้นเรารู้ว่า ARRAY_INIT จะสร้างอาร์เรย์ขึ้นมาเสมอ เราเพียงแค่สร้างอาร์เรย์และเติมข้อมูล เท่าที่คลุมเครือขั้นตอนการวิเคราะห์คำศัพท์มีความโดดเด่นแล้ว ARRAY_INIT จากการเข้าถึงคุณสมบัติของวัตถุ (เช่นobj[foo]
) หรือวงเล็บภายในสตริง / ตัวอักษร regex (เช่น "foo [] บาร์" หรือ / [] /)
นี่คือ miniscule new Array
แต่เรายังมีราชสกุลมากขึ้นด้วย นอกจากนี้ยังไม่ชัดเจนเลยว่าเราเพียงแค่ต้องการสร้างอาร์เรย์ เราเห็นโทเค็น "ใหม่" แต่ "ใหม่" คืออะไร จากนั้นเราจะเห็นโทเค็น IDENTIFIER ซึ่งหมายความว่าเราต้องการ "Array" ใหม่ แต่โดยทั่วไปแล้ว JavaScript ของ VM VM จะไม่แยกโทเค็น IDENTIFIER และโทเค็นสำหรับ "ออบเจ็กต์พื้นเมืองดั้งเดิม" ดังนั้น...
เราต้องค้นหาห่วงโซ่ขอบเขตทุกครั้งที่เราพบโทเค็น IDENTIFIER Javascript VMs มี "วัตถุการเปิดใช้งาน" สำหรับแต่ละบริบทการดำเนินการซึ่งอาจมีวัตถุ "ข้อโต้แย้ง" ตัวแปรที่กำหนดไว้ในเครื่อง ฯลฯ หากเราไม่พบมันในวัตถุการเปิดใช้งานเราจะเริ่มค้นหาห่วงโซ่ขอบเขตจนกว่าจะถึงขอบเขตทั่วโลก . ReferenceError
ถ้าไม่มีอะไรจะพบเราโยน
เมื่อเราพบการประกาศตัวแปรแล้วเราจะเรียกใช้ตัวสร้าง new Array
เป็นการเรียกใช้ฟังก์ชันโดยปริยายและกฎของหัวแม่มือก็คือการเรียกใช้ฟังก์ชั่นจะช้าลงในระหว่างการดำเนินการ (ดังนั้นทำไมคอมไพเลอร์ C / C ++ คงที่อนุญาตให้ "ฟังก์ชั่น inlining" - เครื่องยนต์ JS JIT
ตัวArray
สร้างมีการโอเวอร์โหลด ตัวสร้าง Array มีการใช้งานเป็นรหัสเนทีฟเพื่อให้มีการปรับปรุงประสิทธิภาพบางอย่าง แต่ยังคงต้องตรวจสอบความยาวอาร์กิวเมนต์และดำเนินการตามนั้น ยิ่งไปกว่านั้นในกรณีที่มีอาร์กิวเมนต์เพียงหนึ่งตัวเท่านั้นเราจำเป็นต้องตรวจสอบประเภทของอาร์กิวเมนต์เพิ่มเติม new Array ("foo") สร้าง ["foo"] โดยที่ new Array (1) สร้าง [undefined]
ดังนั้นเพื่อทำให้ง่ายขึ้นทั้งหมด: ด้วยตัวอักษรอาร์เรย์ VM รู้ว่าเราต้องการอาร์เรย์ ด้วยnew Array
, VM ต้องใช้รอบ CPU เพิ่มเติมเพื่อหาว่าnew Array
จริง ๆ แล้วอะไร