2013-09-01 53 views
47

Tôi đang cố gắng gọi các hàm theo nghĩa đen, nhưng tôi nhận được hành vi kỳ lạ.Chức năng gọi thành viên của số

Hãy xem xét mã này trả về true.

23 === (23) 

Khi tôi viết hãy thử làm như sau.

(23).toFixed(2) 

Tôi nhận được kết quả mong đợi _23.00_ nhưng khi tôi thử 23.toFixed(2) Tôi gặp phải lỗi này.

SyntaxError: Unexpected token ILLEGAL

JavaScript đánh giá các biểu thức không thể hiểu điều này và tại sao tôi gặp lỗi này?

Trả lời

58

Câu trả lời của Greg Hewgillicktoofay 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 423e2 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.

+1

Câu trả lời xuất sắc! –

35

Không giống như Ruby (ví dụ), Trình phân tích cú pháp Javascript xem xét . các chữ số sau là một phần của số. Vì vậy, các phân tích cú pháp nhìn thấy các thẻ:

23.toFixed(2)

mà là một lỗi cú pháp, vì từ toFixed ngay sau khi một số dấu chấm động không có ý nghĩa. Một ngôn ngữ như Ruby chấp nhận cú pháp này sẽ thấy các thẻ sau:

23.toFixed(2)

24

xem xét:

5. 

Đó có phải là điểm nổi đen 5. hoặc một số nguyên 5 theo sau là một dấu chấm? Bạn không biết; nó mơ hồ. JavaScript có chế độ xem trước đây. Trong chế độ xem của JavaScript, bạn có một dấu phẩy động theo sau là một số nhận dạng (sau đó theo dấu ngoặc đơn, số và dấu ngoặc đơn bên phải).

Một số người làm việc xung quanh này bằng cách sử dụng hai chấm:

23..toFixed(2) 

Từ một dấu chấm đen chỉ có thể có thể có một dấu thập phân, dấu chấm khác là một dấu chấm đen tượng trưng.

+1

'23.0.toFixed (2)' cũng hoạt động – Ehtesham

Các vấn đề liên quan