Mở rộng hơn nữa về các câu trả lời trước ...
Từ góc độ trình biên dịch chung và bỏ qua các tối ưu hóa dành riêng cho VM:
Đầu tiên, chúng ta trải qua giai đoạn phân tích từ vựng, nơi chúng ta mã hóa mã.
Bằng cách ví dụ, các mã thông báo sau có thể được tạo ra:
[]: 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)
Hy vọng rằng điều này sẽ cung cấp cho bạn một hình ảnh đầy đủ để bạn có thể hiểu được cần phải xử lý nhiều hơn (hoặc ít hơn).
Dựa trên các mã thông báo ở trên, chúng tôi biết rằng thực tế ARRAY_INIT sẽ luôn tạo ra một mảng. Do đó, chúng tôi chỉ đơn giản là tạo ra một mảng và điền vào nó. Theo như sự mơ hồ, giai đoạn phân tích từ vựng đã phân biệt ARRAY_INIT với một trình truy cập thuộc tính đối tượng (ví dụ obj[foo]
) hoặc dấu ngoặc trong chuỗi / regex bằng chữ (ví dụ: "foo [] bar" hoặc / [] /)
Đây là rất nhỏ, nhưng chúng tôi cũng có nhiều mã thông báo hơn new Array
. Hơn nữa, chúng ta không hoàn toàn rõ ràng rằng chúng ta chỉ muốn tạo một mảng. Chúng tôi thấy mã thông báo "mới", nhưng "mới" là gì? Sau đó, chúng tôi thấy mã thông báo IDENTIFIER có nghĩa là chúng tôi muốn có một "Mảng" mới, nhưng nhìn chung JavaScript VM không phân biệt mã thông báo IDENTIFIER và mã thông báo cho "các đối tượng toàn cầu gốc". Vì thế...
Chúng tôi phải tìm kiếm chuỗi phạm vi mỗi lần chúng tôi gặp mã thông báo IDENTIFIER. Máy ảo Javascript chứa "Đối tượng kích hoạt" cho từng bối cảnh thực thi có thể chứa đối tượng "đối số", biến được xác định cục bộ, v.v. Nếu chúng ta không thể tìm thấy nó trong đối tượng Kích hoạt, chúng ta bắt đầu tìm kiếm chuỗi phạm vi cho đến khi chúng ta đạt đến phạm vi toàn cầu . Nếu không có gì được tìm thấy, chúng tôi ném a ReferenceError
.
Khi chúng ta đã định vị khai báo biến, chúng ta gọi hàm tạo. new Array
là một lệnh gọi hàm ẩn và quy tắc chung là các lệnh gọi hàm chậm hơn trong khi thực thi (do đó tại sao trình biên dịch C / C ++ tĩnh cho phép "hàm nội tuyến" - điều mà các công cụ JS JIT như SpiderMonkey phải thực hiện khi đang di chuyển)
Các Array
constructor bị quá tải. Hàm tạo Array được triển khai dưới dạng mã gốc, do đó nó cung cấp một số cải tiến hiệu năng, nhưng nó vẫn cần kiểm tra độ dài đối số và hành động tương ứng. Hơn nữa, trong trường hợp chỉ có một đối số được cung cấp, chúng ta cần kiểm tra thêm loại đối số. Mảng mới ("foo") tạo ra ["foo"] trong đó Mảng mới (1) tạo ra [không xác định]
Vì vậy, để đơn giản hóa tất cả: với các mảng bằng chữ, VM biết chúng ta muốn một mảng; với new Array
, VM cần sử dụng các chu kỳ CPU bổ sung để tìm ra những gì new Array
thực sự làm.