Có 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 dấu ngoặc nhọn (cùng dòng và dòng tiếp theo) không?


91

Hôm nay, khi tôi đang ngẫu nhiên đọc cuốn sách về các mẫu JavaScript O'Reilly, tôi đã tìm thấy một điều thú vị (trang 27 để tham khảo).

Trong Javascript, trong một số trường hợp, có sự khác biệt nếu vị trí bắt đầu dấu ngoặc nhọn 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ó ngôn ngữ nào khác ngoài kia có hành vi như vậy không? Nếu vậy thì chắc chắn tôi sẽ phải thay đổi thói quen của mình .. :)

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


1
Được tái tạo trong Chrome và IE9, bắt tốt: P
gideon

4
Độ nhạy không gian trắng có thể được thực hiện để hoạt động --- hãy nhìn vào chế độ python hoặc chế độ dòng fortran --- nhưng độ nhạy không gian trắng tinh tế là công việc của quỷ. Gah! Điều này cũng tệ như make!
dmckee --- ex-modrator kitten

Thật là ấn tượng! Rất vui!
CheckRaise

Bây giờ tôi muốn biết tại sao javascript hoạt động theo cách này.
CheckRaise

4
@CheckRaise: Tôi tổng hợp các quy tắc ở đây: blog.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Câu trả lời:


53

Bất kỳ ngôn ngữ nào không dựa vào dấu chấm phẩy (mà thay vào đó là dòng mới) để phân tách các câu lệnh đều có thể cho phép điều này. Hãy xem xét Python :

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

Bạn có thể tạo một trường hợp tương tự trong Visual Basic nhưng tôi không thể tìm ra cách vì VB khá hạn chế về nơi các giá trị có thể được đặt. Nhưng những điều sau sẽ hoạt động, trừ khi trình phân tích tĩnh phàn nàn về mã không thể truy cập:

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ữ bạn đã đề cập, Ruby có cùng thuộc tính. PHP, C, C ++ và Java không đơn giản chỉ vì chúng loại bỏ dòng mới dưới dạng 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.

Đây là mã 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 có ý nghĩa vì VB không bao giờ cho phép một câu lệnh kéo dài nhiều dòng trừ khi bạn sử dụng chuỗi tiếp tục dòng "_".
phoog

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

@phoog Đúng, nó hoàn toàn không phải là một gotcha.
Konrad Rudolph

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 (trừ một số trường hợp ngoại lệ, không tham gia vào chúng ở đây :).

Vì vậy, về cơ bản, vấn đề không phải là vị trí của dấu ngoặc nhọn (ở đây đại diện cho một đối tượng theo nghĩa đen, không phải là một khối mã như trong hầu hết các ngôn ngữ), mà là "tính năng" nhỏ này buộc ví dụ đầu tiên của bạn phải return ;=> undefined. Bạn có thể kiểm tra hoạt động của return trong thông số ES5 .

Đối với các ngôn ngữ khác có hành vi tương tự, hãy xem câu trả lời của Konrad .


5
Câu trả lời được ủng hộ cao, nhưng nó thực sự sai, xin lỗi. Lời giải thích là tốt đẹp nhưng xin vui lòng sửa chữa sai lầm.
Konrad Rudolph

Phần nói về JavaScript không sai, cách nó hoạt động giống như nó là do việc chèn dấu chấm phẩy buộc undefinedphải trả về. Tôi đã viết một chút về các ngôn ngữ khác có tiền tố afaik , vì vậy hãy coi nó như một hạt muối :).
Alex Ciminian

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ệ"; đúng hơn, nó thường không chèn dấu chấm phẩy và chỉ có một số trường hợp đúng như vậy . Đó là lý do tại sao nó gây ra rất nhiều gotchas.
ruakh

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ù với các hiệu ứng khác nhau). Như đã giải thích ở đó:

Trên thực tế, điều xảy ra là 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 vào cuối mỗi dòng trông giống như phần cuối của một 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 tạo ra mã trông sạch sẽ, không có dấu chấm phẩy. Một điều ngạc nhiên là điều quan trọng là phải đặt dấu ngoặc nhọn mở đầu của một cấu trúc chẳng hạn như câu lệnh if trên cùng 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ữ buộc kiểu dấu ngoặc nhọn ở một mức độ nào đó.

Một cách bí mật, tôi nghĩ Rob Pike chỉ muốn có một cái cớ để yêu cầu Phong cách Một cái Brace Đúng.


10
Tuyệt, không biết về điều này :). Cá nhân tôi không nghĩ rằng tự động chèn dấu chấm phẩy là một ý kiến ​​hay. Nó có thể đưa ra những lỗi nhỏ mà những người thiếu kinh nghiệm về ngôn ngữ sẽ rất khó tìm ra. Nếu bạn muốn viết mã miễn phí bằng dấu chấm phẩy, tôi thích cách python hơn.
Alex Ciminian

@Alex Các ngôn ngữ chẵn không có bất kỳ dấu chấm phẩy (VB) nào cũng có thuộc tính này. Và Python cũng vậy, bạn có vẻ thích hơn, mặc dù nó xử lý điều này giống hệt với JavaScript.
Konrad Rudolph

Tôi muốn tán thành, ngoại trừ câu thứ hai của bạn sai hoàn toàn đến mức khiến tôi muốn phản đối. Tôi đoán họ hủy bỏ. ;-)
ruakh

1
@ruakh ý bạn là "đi làm chính xác cái này" hay bạn đang ám chỉ câu chuyện cười về cướp pike? Trong trường hợp trước, tôi có thể đặt lại từ ngữ là "thực hiện cùng một hành vi", trong trường hợp sau, tôi xin lỗi nếu khiếu hài hước khập khiễng của tôi gây khó chịu;)
Dave

1
Ý tôi là "Go thực hiện chính xác điều này." Đề xuất ban đầu cho việc chèn dấu chấm phẩy của Go hoàn toàn trái ngược với đề xuất của JavaScript, giải thích rằng, "Đề xuất này có thể nhắc nhở bạn về quy tắc dấu chấm phẩy tùy chọn của JavaScript, có hiệu lực là thêm dấu chấm phẩy để sửa lỗi phân tích cú pháp. Đề xuất Go rất khác", và đó là hoàn toàn đúng, ở mọi cấp độ: nó hoạt động khác nhau, nó có các hiệu ứng khác nhau và hầu như không có lỗi gì. (OTBS-thực thi, mặc dù gây khó chịu, không phải là một gotcha, vì nó là một yêu cầu nhất quán trong tất cả các mã
cờ vây

14

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

return
{
     name: 'rajat'
};

..là công cụ js sẽ chèn dấu chấm phẩy sau return;câu lệnh (và do đó, trả về undefined). Ví dụ này là một lý do chính đáng để mở dấu ngoặc nhọn luôn ở bên phải và không bao giờ ở bên trái. Vì bạn đã nhận thấy chính xác, nếu có dấu ngoặc nhọn trên 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.


6

FWIW, JSLint báo cáo một số cảnh báo với cú pháp đó:

$ 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 gặp phải là awk (ngôn ngữ này cũng có phần cú pháp "kỳ quặc"; dấu chấm phẩy tùy chọn, nối chuỗi chỉ sử dụng khoảng trắng, v.v.) Tôi nghĩ các nhà thiết kế DTrace, dựa trên cú pháp D lỏng lẻo trên awk, có đủ ý thức để KHÔNG sao chép các tính năng này, nhưng tôi không thể nhớ ra khỏi đầu của mình. Một ví dụ đơn giản (đếm số lượng thẻ ENTITY trong 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 tập lệnh nhỏ này được viết với dấu ngoặc nhọn trên một dòng của chính nó, thì đây là điều 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
$ 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.