除JavaScript外,其他任何语言在花括号开始位置(同一行和下一行)之间是否有区别?


91

今天,当我随机阅读O'Reilly的JavaScript模式书籍时,我发现了一件有趣的事情(参考第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演示

那里是否有其他语言有这种行为?如果是这样,那我肯定要改变我的习惯.. :)

我主要关注PHP,C,C ++,Java和ruby。


1
转载于Chrome和IE9,效果不错:P
gideon'2

4
可以使空白敏感度起作用— —例如在python或行模式fortran中— —但是细微的空白敏感度是魔鬼的工作。加!这和make一样糟糕!
dmckee ---前主持人小猫,

这令人印象深刻!好发现!
CheckRaise 2012年

现在,我想知道为什么javascript会这种方式。
CheckRaise 2012年

Answers:


53

任何不依靠分号(而是换行符)来分隔语句的语言都可能允许这样做。考虑Python

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

您可能可以在Visual Basic中构造一个类似的案例,但是我不知道怎么做,因为VB在放置值的位置上有严格的限制。但是,除非静态分析器抱怨无法访问的代码,否则以下内容应该起作用:

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

从您提到的语言来看,Ruby具有相同的属性。PHP,C,C ++和Java不仅因为将换行符作为空格而丢弃,而且需要用分号分隔语句。

以下是Ruby中Python示例的等效代码:

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

2
您的VB示例并没有说明问题,因为除非您使用行继续序列“ _”,否则VB 绝不允许语句跨越多行。
phoog 2012年

2
好吧,我撤消前面的评论,因为我只是看一下规范,VB.NET在某些上下文中支持隐式行连续。我怀疑任何有经验的VB程序员都将这个示例视为“陷阱”,因为它很明显是Throwex.GetBaseException()是分开的逻辑行。更具体地说,由于Basic从前使用行来分隔其语句,因此“陷阱”很可能是程序员认为自己在新的逻辑行上创建了新语句的情况,但事实并非如此。
phoog 2012年

@phoog是的,绝对不是陷阱。
康拉德·鲁道夫

40

;如果没有找到JavaScript解释器,JavaScript解释器会自动在每行的末尾添加一个(有些例外,请不要在此处进入:)。

因此,基本上,问题不是括号的位置(这里表示对象文字,而不是大多数语言中的代码块),而是这个小“功能”,迫使您的第一个示例return ;== undefined。您可以return 在ES5规范中查看的行为。

对于其他具有类似行为的语言,请查看Konrad的答案


5
高度支持的答案,但实际上是错误的,对不起。解释很好,但请更正错误。
康拉德·鲁道夫

关于JavaScript的部分并没有错,它的行为方式就像是因为分号插入会强制undefined返回。我写了一些关于其他语言的前缀afaik的内容,因此请加一点盐:)。
亚历克斯·西米尼安

5
但是JS在“每行的末尾”“有一些例外”插入分号并不是真的。相反,它通常不会插入一个分号,并有它只是少数情况下。这就是为什么它会导致很多陷阱。
ruakh

26

可以肯定。Google的go编程语言表现出非常相似的行为(尽管效果不同)。如此处所述:

实际上,发生的是形式语言使用分号,就像在C或Java中一样,但是它们自动插入到看起来像语句结尾的每一行的末尾。您无需自己输入。

..snip ...

这种方法使代码看起来干净,无分号。令人惊讶的是,将诸如if语句之类的结构的左括号与if放在同一行很重要。如果您不这样做,则某些情况可能无法编译或给出错误的结果。语言在某种程度上强制了大括号样式。

秘密地,我认为Rob Pike只是想借口要求One True Brace Style。


10
很酷,对此一无所知:)。就我个人而言,我不认为自动分号插入是个好主意。它可能会引入一些细微的错误,那些对这种语言缺乏经验的人将很难弄清楚。如果要编写无分号代码,我更喜欢python方式。
Alex Ciminian '02

@Alex即使没有任何分号(VB)的语言也具有此属性。Python也是如此,尽管您的处理方式与JavaScript相同,但您显然更喜欢它。
Konrad Rudolph

我会投票,除了你的第二句话完全错了,使我想投票。我想他们会取消。;-)
ruakh 2012年

1
@ruakh您的意思是“完全做到这一点”还是您指的是关于抢劫派克的笑话?在前一种情况下,我可以改写为“表现出相同的行为”,在后一种情况下,如果我la脚的幽默感冒犯了,我感到抱歉;)
Dave

1
我的意思是“ Go正是这样做的。” Go的分号插入的原始提议与JavaScript明显不同,并解释说:“该提议可能使您想起JavaScript的可选分号规则,该规则实际上添加了分号来修复解析错误。Go提议有很大的不同”,也就是说在每个级别上都非常正确:它的工作原理不同,效果不同,几乎没有陷阱。(OTBS的执行虽然很烦人,但不是陷阱,因为它是所有Go代码中的一致要求。)
ruakh 2012年

14

这个问题的答案很简单。任何具有“自动分号插入”的语言都可能在该行出现问题。这个问题

return
{
     name: 'rajat'
};

..是js引擎将在该return;语句之后插入分号(并因此返回undefined)。这个例子是一个很好的理由,总是在右边打开花括号,也不要在左边打开花括号。由于您已经正确注意到了,如果同一行中有一个大括号,则解释器将注意到这一点,并且不能插入分号。


6

FWIW,JSLint使用该语法报告几个警告:

$ 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

我遇到的第一种语言是awk(也有其语法“奇数”;可选的半冒号,仅使用空格的字符串连接等)。我认为DTrace设计器松散地基于D语法在awk上,我有足够的意识不复制这些功能,但是我不记得了。一个简单的示例(从Mac上计算DTD中的ENTITY标签数量):

$ 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

如果将这个小脚本改写成一行,则将发生以下情况:

$ 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
$ 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.