除了 JavaScript 之外,还有其他语言在大括号开始位置(同一行和下一行)之间有区别吗?

今天,当我在随机阅读 JavaScript 模式 O’Reilly 的书时,我发现了一件有趣的事情(参考第27页)。

在 Javascript 中,在某些情况下,如果大括号的起始位置不同,就会有区别。

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


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

同时

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


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

JSfiddle 演示

Does any other language out there have such behavior? If so, then I would have to change my habit for sure..:)

我主要关注 PHP、 C、 C + + 、 Java 和 Ruby。

2599 次浏览

The JavaScript interpreter automatically adds a ; at the end of each line if it doesn't find one (with some exceptions, not getting into them here :).

So basically the issue is not the braces' location (which here represent an object literal, not a code block as in most languages), but this little "feature" that forces your first example to return ; => undefined. You can check out the behavior of return in the ES5 spec.

For other languages that have similar behavior, check out Konrad's answer.

The answer to that question is fairly easy. Any language that has "automatic semicolon insertion" might be in trouble on that line. The problem with this

return
{
name: 'rajat'
};

..is that the js engine will insert a semicolon after the return; statement (and therefore, return undefined). This example is a good reason to open curly brackets always on the right side and never on the left side also. Since you already correctly noticed, if there is a curly bracket in the same line, the interpretator will notice that and can't insert a semicolon.

Most certainly. Google's go programming language exhibits a very similar behavior (albeit with different effects). As explained there:

In fact, what happens is that the formal language uses semicolons, much as in C or Java, but they are inserted automatically at the end of every line that looks like the end of a statement. You don't need to type them yourself.

..snip...

This approach makes for clean-looking, semicolon-free code. The one surprise is that it's important to put the opening brace of a construct such as an if statement on the same line as the if; if you don't, there are situations that may not compile or may give the wrong result. The language forces the brace style to some extent.

Secretly, I think Rob Pike just wanted an excuse to require the One True Brace Style.

Any language that doesn’t rely on semicolons (but instead on newlines) to delimit statements potentially allows this. Consider Python:

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

You might be able to construct a similar case in Visual Basic but off the top of my head I can’t figure out how because VB is pretty restrictive in where values may be placed. But the following should work, unless the static analyser complains about unreachable code:

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

From the languages you mentioned, Ruby has the same property. PHP, C, C++ and Java do not simply because they discard newline as whitespace, and require semicolons to delimit statements.

Here’s the equivalent code from the Python example in Ruby:

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

FWIW, JSLint reports several warnings with that syntax:

$ 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)

The first language where I came across this was awk (which also has its share of syntax "oddities"; optional semi colons, string concatenation using only whitespace and so on...) I think the DTrace designers, which based the D syntax loosely on awk, had enough sense to NOT copy these features, but I can't remember off the top of my head. A simple example (counting the number of ENTITY tags in a DTD, from my Mac):

$ 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

If this little script instead were written with the brace on a line of its own, this is what would happen:

$ 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
$