Hat eine andere Sprache als JavaScript einen Unterschied zwischen den Startpositionen der Klammern (gleiche Zeile und nächste Zeile)?

91

Als ich heute zufällig das O'Reilly-Buch mit JavaScript-Mustern las, fand ich eine interessante Sache (Seite 27 als Referenz).

In Javascript gibt es in einigen Fällen einen Unterschied, wenn die Startposition der Klammer unterschiedlich ist.

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

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

Während

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

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

JSfiddle Demo

Hat irgendeine andere Sprache da draußen ein solches Verhalten? Wenn ja, dann müsste ich sicher meine Gewohnheit ändern .. :)

Ich mache mir hauptsächlich Sorgen um PHP, C, C ++, Java und Ruby.

Rajat Singhal
quelle
1
Reproduziert in Chrome und IE9, guter Fang: P
Gideon
4
Die Empfindlichkeit des Leerraums kann zum Funktionieren gebracht werden - siehe Python oder Zeilenmodus -, aber die subtile Empfindlichkeit des Leerraums ist die Arbeit des Teufels. Gah! Das ist so schlimm wie machen!
dmckee --- Ex-Moderator Kätzchen
Das ist beeindruckend! Schöner Fund!
CheckRaise
Jetzt möchte ich wissen, warum sich Javascript so verhält.
CheckRaise
4
@CheckRaise: Ich fasse die Regeln hier zusammen: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Antworten:

53

Jede Sprache, die sich nicht auf Semikolons (sondern auf Zeilenumbrüche) stützt, um Anweisungen abzugrenzen, ermöglicht dies möglicherweise. Betrachten Sie Python :

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

Möglicherweise können Sie einen ähnlichen Fall in Visual Basic erstellen, aber auf den ersten Blick kann ich nicht herausfinden, wie, da VB bei der Platzierung von Werten ziemlich restriktiv ist. Folgendes sollte jedoch funktionieren, es sei denn, der statische Analysator beschwert sich über nicht erreichbaren 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

Von den Sprachen, die Sie erwähnt haben, hat Ruby dieselbe Eigenschaft. PHP, C, C ++ und Java verwerfen Newline nicht einfach als Leerzeichen und benötigen Semikolons, um Anweisungen abzugrenzen.

Hier ist der entsprechende Code aus dem Python-Beispiel in Ruby:

>> def foo
>>   return { 1 => 2 }
>> end
=> nil
>> def bar
>>   return
>>   { 1 => 2 }
>> end
=> nil
>> foo
=> {1=>2}
>> bar
=> nil
Konrad Rudolph
quelle
2
Ihr VB-Beispiel macht den Punkt nicht ganz klar, da VB niemals zulässt, dass eine Anweisung mehrere Zeilen umfasst, es sei denn, Sie verwenden die Zeilenfortsetzungssequenz "_".
Phoog
2
Ok, ich ziehe den vorherigen Kommentar zurück, weil ich mir gerade die Spezifikation angesehen habe. Es gibt einige Kontexte, in denen VB.NET implizite Zeilenfortsetzungen unterstützt. Ich bezweifle , jeder erfahrene VB Programmierer in diesem Beispiel eine „Gotcha“ in Betracht ziehen würden, aber da es ziemlich offensichtlich, dass Throwund ex.GetBaseException()sind separate logische Linien. Da Basic in der Vergangenheit Zeilen verwendet, um seine Anweisungen abzugrenzen, ist ein "Gotcha" eher eine Situation, in der ein Programmierer glaubt, eine neue Anweisung in einer neuen logischen Zeile erstellt zu haben, dies jedoch nicht getan hat.
Phoog
@phoog Stimmt, es ist absolut kein Gotcha.
Konrad Rudolph
40

Der JavaScript-Interpreter fügt ;am Ende jeder Zeile automatisch ein hinzu , wenn er keines findet (mit einigen Ausnahmen wird hier nicht darauf eingegangen :).

Im Grunde geht es also nicht um die Position der geschweiften Klammern (die hier ein Objektliteral darstellen, nicht wie in den meisten Sprachen um einen Codeblock), sondern um diese kleine "Funktion", die Ihr erstes Beispiel zu return ;=> zwingt undefined. Sie können das Verhalten return in der ES5-Spezifikation überprüfen .

Weitere Sprachen mit ähnlichem Verhalten finden Sie in Konrads Antwort .

Alex Ciminian
quelle
5
Hochgelobte Antwort, aber es ist tatsächlich falsch, sorry. Die Erklärung ist nett, aber bitte korrigieren Sie den Fehler.
Konrad Rudolph
Der Teil über JavaScript ist nicht falsch. Das Verhalten ist auf die Semikolon-Einfügung zurückzuführen, die undefineddie Rückgabe erzwingt . Ich habe das Stück über die anderen Sprachen geschrieben, denen afaik vorangestellt ist , also nimm es mit einem Körnchen Salz :).
Alex Ciminian
5
Es ist jedoch nicht wahr, dass JS ein Semikolon "am Ende jeder Zeile" "mit einigen Ausnahmen" einfügt. Vielmehr wird normalerweise kein Semikolon eingefügt, und es gibt nur wenige Fälle, in denen dies der Fall ist . Deshalb verursacht es so viele Fallstricke.
Ruakh
26

Höchstwahrscheinlich. Die Programmiersprache go von Google zeigt ein sehr ähnliches Verhalten (wenn auch mit unterschiedlichen Effekten). Wie dort erklärt:

Tatsächlich verwendet die formale Sprache Semikolons, ähnlich wie in C oder Java, aber sie werden automatisch am Ende jeder Zeile eingefügt, die wie das Ende einer Anweisung aussieht. Sie müssen sie nicht selbst eingeben.

..snip ...

Dieser Ansatz sorgt für sauber aussehenden, semikolonfreien Code. Die einzige Überraschung ist, dass es wichtig ist, die öffnende Klammer eines Konstrukts wie eine if-Anweisung in dieselbe Zeile wie das if zu setzen. Wenn Sie dies nicht tun, gibt es Situationen, die möglicherweise nicht kompiliert werden oder zu einem falschen Ergebnis führen können. Die Sprache erzwingt den Klammerstil in gewissem Maße.

Insgeheim denke ich, dass Rob Pike nur eine Ausrede wollte, um den One True Brace Style zu fordern.

Dave
quelle
10
Cool, wusste nichts davon :). Persönlich halte ich das automatische Einfügen von Semikolons nicht für eine gute Idee. Es kann subtile Fehler verursachen, die Menschen, die mit der Sprache unerfahren sind, nur schwer herausfinden können. Wenn Sie semikolonfreien Code schreiben möchten, bevorzuge ich die Python-Methode.
Alex Ciminian
@ Alex Auch Sprachen ohne jegliche Semikolons (VB) haben diese Eigenschaft. Und Python, das Sie anscheinend bevorzugen, obwohl es dies genauso wie JavaScript behandelt.
Konrad Rudolph
Ich würde zustimmen, außer dass Ihr zweiter Satz so völlig falsch ist, dass ich abstimmen möchte. Ich denke, sie heben sich auf. ;-)
Ruakh
1
@ruakh meinst du "go macht genau das" oder hast du dich auf den Witz über Rob Pike bezogen? Im ersteren Fall könnte ich umformulieren, dass "go das gleiche Verhalten zeigt", im letzteren Fall tut es mir leid, wenn mein lahmer Sinn für Humor verletzt wird;)
Dave
1
Ich meine das "Go macht genau das." Der ursprüngliche Vorschlag für das Einfügen von Semikolons von Go steht in explizitem Gegensatz zu dem von JavaScript und erklärt: "Dieser Vorschlag erinnert Sie möglicherweise an die optionale Semikolonregel von JavaScript, mit der Semikolons hinzugefügt werden, um Analysefehler zu beheben. Der Go-Vorschlag unterscheidet sich grundlegend." Ganz richtig, auf jeder Ebene: Es funktioniert anders, es hat unterschiedliche Effekte und es hat fast keine Fallstricke. (OTBS-Durchsetzung ist zwar ärgerlich, aber kein Problem, da es eine konsistente Anforderung in allen Go-Codes ist.)
Ruakh
14

Die Antwort auf diese Frage ist ziemlich einfach. Jede Sprache mit "automatischer Semikoloneinfügung" kann in dieser Zeile in Schwierigkeiten geraten. Das Problem damit

return
{
     name: 'rajat'
};

..ist, dass die js-Engine nach der return;Anweisung ein Semikolon einfügt (und daher zurückgibt undefined). Dieses Beispiel ist ein guter Grund, geschweifte Klammern immer auf der rechten Seite und niemals auch auf der linken Seite zu öffnen . Da Sie bereits richtig bemerkt haben, wird der Interpreter dies bemerken und kann kein Semikolon einfügen, wenn sich in derselben Zeile eine geschweifte Klammer befindet.

jAndy
quelle
6

FWIW, JSLint meldet mehrere Warnungen mit dieser 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)
Brandan
quelle
1

Die erste Sprache, in der ich darauf gestoßen bin, war awk (die auch einen Teil der Syntax "Kuriositäten" aufweist; optionale Semikolons, String-Verkettung nur mit Leerzeichen usw.). Ich denke, die DTrace-Designer, die die D-Syntax lose basierten Ich hatte genug Sinn, diese Funktionen NICHT zu kopieren, aber ich kann mich nicht mehr an meinen Kopf erinnern. Ein einfaches Beispiel (Zählen der Anzahl der ENTITY-Tags in einer DTD von meinem Mac aus):

$ 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

Wenn dieses kleine Skript stattdessen mit der Klammer in einer eigenen Zeile geschrieben würde, würde Folgendes passieren:

$ 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
$ 
Anders S.
quelle