91

Hôm nay, trong khi tôi đọc ngẫu nhiên các mẫu sách O'Reilly, tôi đã tìm thấy một điều thú vị (trang 27 để tham khảo).Có bất kỳ ngôn ngữ nào khác ngoài JavaScript có sự khác biệt giữa các vị trí bắt đầu cú đúp (cùng dòng và dòng tiếp theo) không?

Trong Javascript, trong một số trường hợp, có sự khác biệt nếu vị trí bắt đầu cú đúp khác nhau.

function test_function1() { 
    return 
    { 
     name: 'rajat' 
    }; 
} 

var obj = test_function1(); 
alert(obj); //Shows "undefined" 

Trong khi

function test_function2() { 
    return { 
     name: 'rajat' 
    }; 
} 

var obj = test_function2(); 
alert(obj); //Shows object 

JSfiddle Demo

Có bất kỳ ngôn ngữ nào khác ngoài kia có hành vi như vậy? Nếu vậy, thì tôi sẽ phải thay đổi thói quen của mình chắc chắn .. :)

Tôi chủ yếu quan tâm đến PHP, C, C++, Java và ruby.

+1

sao chép trong Chrome và IE9, tốt bắt: P – gideon

+4

trắng không gian nhạy cảm có thể được thực hiện để làm việc --- nhìn vào python hoặc chế độ dòng fortran --- nhưng * tinh tế * nhạy khoảng trắng là công việc của ác quỷ. Gah! Điều này là xấu như thực hiện! – dmckee

+0

Điều này thật ấn tượng! Nice tìm! – CheckRaise

Trả lời

53

Mọi ngôn ngữ không dựa vào dấu chấm phẩy (nhưng thay vì trên dòng mới) để phân tách các câu lệnh có khả năng cho phép điều này. Cân nhắc Python:

>>> def foo(): 
... return 
... { 1: 2 } 
... 
>>> def bar(): 
... return { 1: 2 } 
... 
>>> foo() 
>>> bar() 
{1: 2} 

Bạn có thể có thể để xây dựng một trường hợp tương tự trong Visual Basic nhưng ra khỏi đỉnh đầu của tôi Tôi không thể tìm ra cách vì VB là khá hạn chế trong đó các giá trị có thể được đặt. Nhưng những điều sau đây nên làm việc, trừ trường hợp phân tích tĩnh phàn nàn mã về unreachable:

Try 
    Throw New Exception() 
Catch ex As Exception 
    Throw ex.GetBaseException() 
End Try 

' versus 

Try 
    Throw New Exception() 
Catch ex As Exception 
    Throw 
    ex.GetBaseException() 
End Try 

Từ các ngôn ngữ mà bạn đề cập, của Ruby có tính chất tương tự. PHP, C, C++ và Java không đơn giản chỉ vì chúng loại bỏ dòng mới là khoảng trắng và yêu cầu dấu chấm phẩy để phân tách các câu lệnh.

Dưới đây là đoạn code tương đương từ ví dụ Python trong Ruby:

>> def foo 
>> return { 1 => 2 } 
>> end 
=> nil 
>> def bar 
>> return 
>> { 1 => 2 } 
>> end 
=> nil 
>> foo 
=> {1=>2} 
>> bar 
=> nil 
+2

Ví dụ VB của bạn không hoàn toàn làm cho điểm vì VB * không bao giờ * cho phép một câu lệnh mở rộng nhiều dòng trừ khi bạn sử dụng chuỗi tiếp tục dòng "_". – phoog

+2

Ok Tôi rút lại nhận xét trước đó vì tôi chỉ xem xét thông số có một số ngữ cảnh trong đó VB.NET hỗ trợ các dòng tiếp tục ngầm. Tôi nghi ngờ bất kỳ lập trình VB có kinh nghiệm sẽ xem xét ví dụ này là một "gotcha", tuy nhiên, vì nó khá rõ ràng rằng 'Throw' và' ex.GetBaseException() 'là những dòng logic riêng biệt. Cụ thể hơn, vì sử dụng các dòng cơ bản để phân định các câu lệnh của nó, một "gotcha" có thể sẽ là một tình huống mà một lập trình viên nghĩ rằng anh ta đã tạo ra một tuyên bố mới trên một dòng logic mới, nhưng không. – phoog

+0

@phoog Đúng, nó hoàn toàn không phải là một hình ảnh xác thực. –

40

Trình thông dịch JavaScript tự động thêm ; vào cuối mỗi dòng nếu không tìm thấy một (với một số ngoại lệ, không đi vào chúng tại đây :). Vì vậy, về cơ bản vấn đề không phải là vị trí của niềng răng (mà ở đây đại diện cho một đối tượng theo nghĩa đen, không phải là khối mã như trong hầu hết các ngôn ngữ), nhưng "tính năng" nhỏ này buộc ví dụ đầu tiên của bạn là return ; =>undefined. Bạn có thể kiểm tra hành vi của returnin the ES5 spec.

Đối với các ngôn ngữ khác có hành vi tương tự, hãy xem Konrad's answer.

+5

Câu trả lời được đánh giá cao, nhưng thực sự là sai, lấy làm tiếc. Lời giải thích rất hay nhưng hãy sửa lỗi. –

+0

Một phần về JavaScript không sai, cách nó hoạt động giống như nó là do chèn dấu chấm phẩy buộc 'undefined' được trả về. Tôi đã viết một chút về các ngôn ngữ khác bắt đầu bằng _afaik_, vì vậy hãy lấy nó bằng một hạt muối :). –

+5

Nhưng không đúng khi JS chèn một dấu chấm phẩy "ở cuối mỗi dòng" "với một số ngoại lệ"; thay vào đó, nó thường * không * chèn một dấu chấm phẩy, và chỉ có một vài trường hợp mà nó * không *. Đó là lý do tại sao nó gây ra rất nhiều gotchas. – ruakh

14

Câu trả lời cho câu hỏi đó khá dễ dàng. Bất kỳ ngôn ngữ nào có "chèn dấu chấm phẩy tự động" có thể gặp sự cố trên dòng đó. Vấn đề ở đây

return 
{ 
    name: 'rajat' 
}; 

..is rằng động cơ js sẽ chèn một dấu chấm phẩy sau khi tuyên bố return; (và do đó, trở về undefined). Ví dụ này là một lý do tốt để mở ngoặc nhọn luôn luôn ở bên phải và không bao giờ ở bên trái cũng vậy. Vì bạn đã nhận thấy chính xác, nếu có dấu ngoặc nhọn trong cùng một dòng, trình thông dịch sẽ nhận thấy điều đó và không thể chèn dấu chấm phẩy.

26

Chắc chắn nhất. Ngôn ngữ lập trình go của Google thể hiện một hành vi rất giống nhau (mặc dù có các hiệu ứng khác nhau). Như đã giải thích ở đó:

Thực tế, ngôn ngữ chính thức sử dụng dấu chấm phẩy, giống như trong C hoặc Java, nhưng chúng được chèn tự động ở cuối mỗi dòng giống như kết thúc câu lệnh. Bạn không cần phải tự mình nhập chúng.

..snip ...

Cách tiếp cận này làm cho mã sạch-looking, dấu chấm phẩy-miễn phí. Điều đáng ngạc nhiên là điều quan trọng là đặt dấu ngoặc mở của một cấu trúc như câu lệnh if trên cùng một dòng với if; nếu bạn không, có những tình huống có thể không biên dịch hoặc có thể cho kết quả sai. Ngôn ngữ này buộc phong cách cú đúp ở một mức độ nào đó.

Bí mật, tôi nghĩ Rob Pike chỉ muốn một cái cớ để yêu cầu một kiểu dấu ngoặc nhọn thực.

+10

Tuyệt, không biết về điều này :). Cá nhân, tôi không nghĩ rằng chèn dấu chấm phẩy tự động là một ý tưởng hay. Nó có thể giới thiệu các lỗi tinh tế mà mọi người thiếu kinh nghiệm với ngôn ngữ sẽ có một thời gian khó khăn để tìm ra. Nếu bạn muốn viết mã dấu chấm phẩy miễn phí, tôi thích cách python. –

+0

@Alex Ngay cả các ngôn ngữ không có * bất kỳ * dấu chấm phẩy (VB) nào có thuộc tính này. Và do đó, Python, mà bạn dường như thích, mặc dù nó xử lý này giống hệt với JavaScript. –

+0

Tôi muốn upvote, ngoại trừ câu thứ hai của bạn là như vậy hoàn toàn sai lầm mà nó làm cho tôi muốn downvote. Tôi đoán họ hủy bỏ.;-) – ruakh

6

FWIW, JSLint báo cáo một vài cảnh báo với cú pháp rằng:

$ jslint -stdin 
function foo(){ 
    return 
    { x: "y" }; 
} 
^D 
(3): lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement 
    return 
........^ 

(3): lint warning: missing semicolon 
    { x: "y" }; 
..^ 

(3): lint warning: unreachable code 
    { x: "y" }; 
..^ 

(3): lint warning: meaningless block; curly braces have no impact 
    { x: "y" }; 
..^ 

(3): lint warning: use of label 
    { x: "y" }; 
.....^ 

(3): lint warning: missing semicolon 
    { x: "y" }; 
...........^ 

(3): lint warning: empty statement or extra semicolon 
    { x: "y" }; 
............^ 


0 error(s), 7 warning(s) 
1

Ngôn ngữ đầu tiên mà tôi tình cờ này đã awk (cũng có phần chia sẻ cú pháp "kỳ quặc", dấu chấm phẩy tùy chọn, nối chuỗi chỉ bằng khoảng trắng ... vv Tôi nghĩ rằng các nhà thiết kế DTrace, dựa trên cú pháp D lỏng lẻo trên awk, có đủ ý nghĩa để KHÔNG sao chép thes e tính năng, nhưng tôi không thể nhớ ra khỏi đỉnh đầu của tôi. Một ví dụ đơn giản (đếm số lượng thẻ ENTITY trong một DTD, từ máy Mac của tôi):

$ cat printEntities.awk 
# This prints all lines where the string ENTITY occurs 
/ENTITY/ { 
    print $0 
} 
$ awk -f printEntities.awk < /usr/share/texinfo/texinfo.dtd | wc -l 
    119 

Nếu kịch bản này ít thay vì được viết với cú đúp trên một dòng riêng của mình, đây là những gì sẽ xảy ra:

$ cat printAll.awk 
# Because of the brace placement, the print statement will be executed 
# for all lines in the input file 
# Lines containing the string ENTITY will be printed twice, 
# because print is the default action, if no other action is specified 
/ENTITY/ 
{ 
    print $0 
} 
$ awk -f printAll.awk < /usr/share/texinfo/texinfo.dtd | wc -l 
    603 
$ /bin/cat < /usr/share/texinfo/texinfo.dtd | wc -l 
    484 
$ 
Các vấn đề liên quan