Câu trả lời của Greg Hewgill và icktoofay là chính xác theo mọi cách, tuy nhiên, tôi muốn suy giảm một chút, trừu tượng khôn ngoan: Hãy xem điều gì thực sự xảy ra theo đặc tả javascript.
Section 7.8.3 của spec xác định chữ số. Chúng ta có thể thấy như sau:
DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
. DecimalDigits ExponentPart(opt)
DecimalIntegerLiteral ExponentPart(opt)
DecimalIntegerLiteral ::
0
NonZeroDigit DecimalDigits(opt)
Một DecimalLiteral
, một số, là một loạt các chữ số thập phân, có thể theo sau bởi một dấu chấm, mà cũng có tiềm năng tiếp theo chữ số khác (tất cả đều có thể được theo sau bởi một số mũ, Ví dụ: e12
). Nói cách khác, 42.
là hợp pháp và bằng 42
và 3e2
bằng 300
.
Lưu ý cách nếu chúng tôi có dấu chấm, chúng tôi hy vọng nó sẽ được theo sau bởi nhiều chữ số/số mũ, hoặc không được theo sau bởi không có gì. Tuy nhiên, và đây là phần quan trọng, chấm là một phần của số. Hãy nhớ điều này khi chúng tôi di chuyển để xem cách toán tử dấu chấm, obj.prop
, được xử lý.
Section 11.2.1, Property Accessors mô tả các dấu chấm và ký hiệu khung cho việc truy cập thành viên:
MemberExpression . IdentifierName
CallExpression
là cho các cuộc gọi chức năng, mà chúng tôi không quan tâm. Hãy lưu ý cách chúng tôi đang mong đợi một số MemberExpression
(có thể là DecimalLiteral
- nhưng đừng dùng từ ngữ của tôi để xem, xem và xem tôi có đúng hay không).
Thấy dấu chấm nhỏ đó? Nó hợp lý để nhảy về phía trước và nói "tốt, có một dấu chấm trong sơ đồ ở đây ... và có một dấu chấm trong 4.foo
... vậy tại sao lại có lỗi?" Alas người bạn giả định của tôi mà tôi sử dụng cho những câu này, bạn quên cách DecimalLiteral
trông như thế nào! Hãy xem xét hai ví dụ và xem điều gì sẽ xảy ra.
42.foo
^
Dấu mũ đại diện cho ký tự chúng tôi đang sử dụng. Cho đến nay, chúng tôi đang ở bên trong DecimalLiteral/DecimalIntegerLiteral/NonZeroDigit
(đó là khá một ngụm). Hãy chuyển sang ký tự tiếp theo:
42.foo
^
Vẫn là một phần của số, hoàn toàn hợp lệ DecimalDigit
.
42.foo
^
ok, vì vậy chúng tôi sẽ ra khỏi phần DecimalIntegerLiteral
. Đây là sơ đồ tương tự trên lược đồ:
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
^
Vì vậy, chúng tôi đang ở trên một dấu chấm, là một phần hoàn toàn hợp lệ của một số. Bây giờ chúng ta tiêu thụ nó, như một phần của số, và di chuyển trên:
42.foo
^
f
không phải là một phần của DecimalDigits
hay của ExponentPart
, chúng tôi ra khỏi số bây giờ. Giờ thì sao? Đó là gì f
? Nó không phải là một phần của bất cứ điều gì. Có lẽ đó là một accessor tài sản? Chúng ta hãy nhìn vào chương trình này:
MemberExpression . IdentifierName
^
Chúng tôi chắc chắn trên MemberExpression
, nhưng chúng tôi không có một dấu chấm mà sau nó - dot rằng đã là một phần của số. Chúng tôi đã gặp lỗi cú pháp: chúng tôi ngừng thực hiện và ném nó. Hy vọng rằng bạn không sống trong một ngôi nhà kính.
Hy vọng rằng bây giờ bạn đã hiểu tại sao 42..foo
hoạt động. Khi chúng tôi ra khỏi MemberExpression
, chúng ta phải đối mặt với một dấu chấm:
42..foo
^
MemberExpression . IdentifierName
^
Tiếp theo là một hoàn toàn hợp pháp IdentifierName
.
Tất nhiên, có một số cách khác để tách dấu chấm khỏi số. Một cách, như bạn đã chỉ ra, là bao quanh chữ cái trong dấu ngoặc đơn: (42).foo
. Khi chúng tôi đã đạt đến dấu ngoặc đơn, chúng tôi sẽ thoát khỏi số MemberExpression
và trên chấm.Một cách khác là chèn một không gian: 42 .foo
, vì không gian không thể là một phần của số, và nó là trung lập cho trình phân tích cú pháp, do đó nó sẽ không gây ra lỗi.
Câu trả lời xuất sắc! –