2013-07-11 43 views
25

MDN states rằng có hai nhà khai thác trong javscript rằng chia sẻ những ưu tiên cao nhất:Tại sao "new Date(). ToString()" làm việc cho ưu tiên toán tử Javascript?

  • Thành viên trái kết hợp điều hành: foo.bar
  • Quyền-kết hợp điều hành mới: new Foo()

Tôi thường một cách rõ ràng tách hai: (new Date()).toString()
Nhưng tôi thường thấy cả hai kết hợp được kết hợp: new Date().toString()

Theo this answer, lý do cách thứ hai hoạt động là đó là sự kết hợp của toán tử thứ hai quan trọng khi cả hai toán tử có quyền ưu tiên bằng nhau. Trong trường hợp này, toán tử thành viên là liên kết trái nghĩa là new Date() được đánh giá trước tiên.

Tuy nhiên, nếu đúng như vậy, thì tại sao new Date.toString() không thành công? Sau cùng, new Datejust syntactic sugar cho new Date(). Các đối số trên nói rằng nó sẽ làm việc, nhưng rõ ràng là không.

Tôi đang thiếu gì?

+1

Bởi vì đường cú pháp không mở rộng đến instantiation VÀ truy cập thành viên. Nó phụ thuộc vào trình biên dịch. Kịch bản tương tự: VB.NET có 'Dim x As New ...' nhưng tôi không tin rằng chúng ta có thể làm 'Dim x As New Date(). ToString()'. Chúng ta có thể làm 'Dim x As String = new Date(). ToString()'. – ps2goat

+1

Toán tử '()' sẽ thực hiện hàm tạo trước khi '.' truy cập các thuộc tính của nó. – Broxzier

+0

@ ps2goat Bạn nói đúng, nhưng dựa trên câu trả lời dưới đây là do ngữ pháp được chỉ định chứ không phải là trình biên dịch hay thay đổi. –

Trả lời

19

Các syntax

MemberExpression : 
    PrimaryExpression 
    FunctionExpression 
    MemberExpression [ Expression ] 
    MemberExpression . IdentifierName 
    new MemberExpression Arguments 

new foo().bar không thể được phân tích như new (foo().bar)foo().bar không phải là một MemberExpression. Hơn nữa, không thể phân tích cú pháp new foo() thành new (foo()), vì lý do tương tự. Ngược lại, new foo.bar được phân tích cú pháp là new (foo.bar)foo.bar là MemberExpression hợp lệ (không thể diễn giải (new foo).bar vì ngữ pháp tham lam).

Tức là, quy tắc ưu tiên là: dấu chấm đập mới, cuộc gọi nhịp đập mới (parens).

. -> new ->() 

Hơn nữa, nhìn thẳng vào ngữ pháp Tài liệu làm rõ các đường cú pháp có thể biến new Foo vào new Foo(). Nó chỉ đơn giản NewExpression ← NewExpression mới ← PrimaryExpression mới:

NewExpression : 
    MemberExpression 
    new NewExpression 
5

Tôi là anh chàng người đã viết cả câu hỏi và câu trả lời của "Disambiguation of expressions with neighboring operators of different associativity and same precedence", và khi tôi viết rằng tôi không có JavaScript trong tâm trí của tôi.

Ngôn ngữ tôi đang xem xét là Haskell, một ngôn ngữ lập trình chức năng. Các toán tử trong các ngôn ngữ như vậy chỉ đơn giản là chức năng và dễ dàng hơn nhiều để giải thích. Tuy nhiên tôi đã viết câu trả lời của tôi theo cách mà không có bất kỳ ngôn ngữ lập trình nào.

Mặt khác, JavaScript là ngôn ngữ lập trình truyền thống và các biểu thức trong JavaScript được định hướng dựa trên các quy tắc phân tích phức tạp rất khác với quy tắc phân tích cú pháp do Haskell sử dụng.

Trong quy tắc phân tích cú pháp JavaScript cụ thể có vẻ tham lam.Ví dụ lấy ví dụ đầu tiên của bạn:

new Date().toString() 

Ở đây, chức năng cuộc gọi sau khi Date lá chắn Date từ các nhà điều hành viên. Do đó, new, đang tham lam, vẫn có thể hoạt động trên Date thay vì Date().toString. Do đó ta có:

((new Date()).toString)() 

Trong ví dụ thứ hai chúng ta có:

new Date.toString() 

Ở đây không có gọi hàm sau Date để bảo vệ nó từ các nhà điều hành viên. Do đó new, tham lam, hoạt động trên biểu thức Date.toString. Do đó chúng tôi có:

(new (Date.toString))() 

Câu trả lời của @ thg435 sao lưu xác nhận quyền sở hữu này. Vấn đề là tôi đã thảo luận về một hệ thống chính thức hoàn toàn khác với hệ thống được thực hiện bởi các trình phân tích cú pháp JavaScript. Hệ thống chính thức mà tôi đã thảo luận về các toán tử xử lý và toán hạng cả hai đều là các giá trị lớp đầu tiên.

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