599 Stimmen

Wie lauten die Regeln für die automatische Semikoloneinfügung (ASI) von JavaScript?

Nun, zunächst einmal sollte ich fragen, ob dies browserabhängig ist.

Ich habe gelesen, dass, wenn ein ungültiges Token gefunden wird, aber der Codeabschnitt bis zu diesem ungültigen Token gültig ist, ein Semikolon vor dem Token eingefügt wird, wenn diesem ein Zeilenumbruch vorausgeht.

Das häufigste Beispiel für Fehler, die durch das Einfügen von Semikolons verursacht werden, ist jedoch das folgende:

return
  _a+b;

was nicht dieser Regel zu entsprechen scheint, da _a ein gültiges Token wäre.

Andererseits funktioniert das Aufbrechen von Anrufketten wie erwartet:

$('#myButton')
  .click(function(){alert("Hello!")});

Hat jemand eine detailliertere Beschreibung der Regeln?

595voto

Christian C. Salvadó Punkte 763569

Zunächst einmal sollten Sie wissen, welche Anweisungen von der automatischen Semikoloneinfügung (der Einfachheit halber auch ASI genannt) betroffen sind:

  • leere Erklärung
  • var Anweisung
  • Ausdrucksanweisung
  • do-while Anweisung
  • continue Anweisung
  • break Anweisung
  • return Anweisung
  • throw Anweisung

Die konkreten Regeln von ASI sind in der Spezifikation beschrieben §11.9.1 Regeln für das automatische Einfügen von Semikolons

Es werden drei Fälle beschrieben:

  1. Wenn ein Token auftritt, das nach der Grammatik nicht zulässig ist, wird ein Semikolon vor dem Token eingefügt, wenn:
  • Das Token ist vom vorherigen Token durch mindestens ein LineTerminator .
  • Der Token ist }

z.B.. :

    { 1
    2 } 3

wird umgewandelt in

    { 1
    ;2 ;} 3;

El NumericLiteral 1 die erste Bedingung erfüllt, ist das folgende Token ein Zeilenabschlusszeichen.
El 2 die zweite Bedingung erfüllt, ist das folgende Token } .

  1. Wenn das Ende des Eingabestroms von Token erreicht wird und der Parser nicht in der Lage ist, den Eingabestrom von Token als einzelnes vollständiges Programm zu parsen, wird automatisch ein Semikolon am Ende des Eingabestroms eingefügt.

z.B.. :

    a = b
    ++c

umgewandelt wird:

    a = b;
    ++c;
  1. Dieser Fall tritt ein, wenn ein Token durch eine Produktion der Grammatik erlaubt ist, aber die Produktion ein eingeschränkte Produktion wird automatisch ein Semikolon vor dem eingeschränkten Token eingefügt.

Eingeschränkte Produktionen:

    UpdateExpression :
        LeftHandSideExpression [no LineTerminator here] ++
        LeftHandSideExpression [no LineTerminator here] --

    ContinueStatement :
        continue ;
        continue [no LineTerminator here] LabelIdentifier ;

    BreakStatement :
        break ;
        break [no LineTerminator here] LabelIdentifier ;

    ReturnStatement :
        return ;
        return [no LineTerminator here] Expression ;

    ThrowStatement :
        throw [no LineTerminator here] Expression ; 

    ArrowFunction :
        ArrowParameters [no LineTerminator here] => ConciseBody

    YieldExpression :
        yield [no LineTerminator here] * AssignmentExpression
        yield [no LineTerminator here] AssignmentExpression

Das klassische Beispiel, mit dem ReturnStatement :

    return 
      "something";

wird umgewandelt in

    return;
      "something";

66voto

nonopolarity Punkte 138211

Ich konnte diese 3 Regeln in den Spezifikationen nicht so gut verstehen - ich hoffe, dass ich etwas habe, das einfacheres Englisch ist - aber hier ist, was ich aus JavaScript entnommen habe: The Definitive Guide, 6th Edition, David Flanagan, O'Reilly, 2011:

Zitat:

JavaScript behandelt nicht jeden Zeilenumbruch als Semikolon: Normalerweise werden Zeilenumbrüche nur dann als Semikolon behandelt, wenn der Code ohne die Semikolons nicht geparst werden kann.

Ein weiteres Zitat: für den Code

var a
a
=
3 console.log(a)

JavaScript behandelt den zweiten Zeilenumbruch nicht als Semikolon, da es mit der Analyse der längeren Anweisung a = 3 fortfahren kann;

und:

zwei Ausnahmen von der allgemeinen Regel, dass JavaScript Zeilenumbrüche als Semikolons interpretiert, wenn es die zweite Zeile nicht als Fortsetzung der Anweisung in der ersten Zeile analysieren kann. Die erste Ausnahme betrifft die return-, break- und continue-Anweisungen

... Wenn ein Zeilenumbruch nach einem dieser Wörter erscheint ... wird JavaScript diesen Zeilenumbruch immer als Semikolon interpretieren.

... Die zweite Ausnahme betrifft die Operatoren ++ und ... Wenn Sie einen dieser Operatoren als Postfix-Operator verwenden wollen, müssen sie in derselben Zeile stehen wie der Ausdruck, auf den sie sich beziehen. Andernfalls wird der Zeilenumbruch wie ein Semikolon behandelt, und ++ oder -- werden als Präfix-Operatoren auf den folgenden Code angewendet. Betrachten Sie zum Beispiel diesen Code:

x 
++ 
y

Sie wird geparst als x; ++y; , nicht als x++; y

Ich denke, vereinfacht ausgedrückt, bedeutet dies:

Im Allgemeinen wird JavaScript es als Fortsetzung des Codes behandeln, solange es Sinn macht -- außer in 2 Fällen: (1) nach einigen Schlüsselwörtern wie return , break , continue , und (2) wenn es sieht ++ ou -- in eine neue Zeile einfügen, dann wird die ; am Ende der vorherigen Zeile.

Der Teil über "behandeln es als Fortsetzung des Codes, solange es Sinn macht" macht es das Gefühl, wie reguläre Ausdrücke gierig Matching.

Dies bedeutet, dass für return mit einem Zeilenumbruch, fügt der JavaScript-Interpreter ein ;

(erneut zitiert: Wenn ein Zeilenumbruch nach einem dieser Wörter erscheint [wie return ] ... JavaScript wird diesen Zeilenumbruch immer als Semikolon interpretieren)

und aus diesem Grund ist das klassische Beispiel für

return
{ 
  foo: 1
}

wird nicht wie erwartet funktionieren, weil der JavaScript-Interpreter es als behandelt:

return;   // returning nothing
{
  foo: 1
}

Es darf kein Zeilenumbruch unmittelbar nach der return :

return { 
  foo: 1
}

damit es richtig funktioniert. Und Sie können eine ; selbst, wenn Sie die Regel befolgen würden, eine ; nach jeder Anweisung:

return { 
  foo: 1
};

53voto

Jörg W Mittag Punkte 349574

Direkt aus dem ECMA-262, Fünfte Ausgabe der ECMAScript-Spezifikation :

7.9.1 Regeln für das automatische Einfügen von Semikolons

Es gibt drei Grundregeln für das Einfügen von Semikolons:

  1. Wenn das Programm von links nach rechts geparst wird, wird ein Token (genannt fehlerhaftes Zeichen ) auf ein Token stößt, das in keiner Produktion der Grammatik erlaubt ist, wird automatisch ein Semikolon vor dem entsprechenden Token eingefügt, wenn eine oder mehrere der folgenden Bedingungen erfüllt sind:
    • Das verletzende Token ist vom vorherigen Token durch mindestens ein LineTerminator .
    • Das beanstandete Token ist } .
  2. Wenn beim Parsen des Programms von links nach rechts das Ende des Eingabestroms von Token erreicht wird und der Parser nicht in der Lage ist, den Eingabestrom von Token als einen einzelnen vollständigen ECMAScript Program dann wird am Ende des Eingabestroms automatisch ein Semikolon eingefügt.
  3. Wenn beim Parsen des Programms von links nach rechts ein Token auftaucht, das von einer Produktion der Grammatik zugelassen wird, aber die Produktion ist eine eingeschränkte Produktion und das Token wäre das erste Token für ein Terminal oder Nonterminal unmittelbar nach der Anmerkung " [nein <code>LineTerminator</code> hier] " innerhalb der eingeschränkten Produktion (und daher wird ein solches Token ein eingeschränktes Token genannt), und das eingeschränkte Token ist vom vorherigen Token durch mindestens ein LineTerminator dann wird automatisch ein Semikolon vor dem eingeschränkten Token eingefügt.

Es gibt jedoch eine zusätzliche Bedingung zu den vorangegangenen Regeln: Ein Semikolon wird niemals automatisch eingefügt, wenn das Semikolon dann als leere Anweisung geparst würde oder wenn dieses Semikolon zu einem der beiden Semikolons in der Kopfzeile einer for Anweisung (siehe 12.6.3).

19voto

Dexygen Punkte 12014

Was die Einfügung des Semikolons und die var-Anweisung betrifft, so sollten Sie darauf achten, dass Sie das Komma vergessen, wenn Sie var verwenden und sich über mehrere Zeilen erstrecken. Jemand hat das gestern in meinem Code gefunden:

    var srcRecords = src.records
        srcIds = [];

Es lief, aber der Effekt war, dass die srcIds-Deklaration/Zuweisung global war, weil die lokale Deklaration mit var in der vorherigen Zeile nicht mehr galt, da diese Anweisung aufgrund der automatischen Einfügung des Semikolons als abgeschlossen betrachtet wurde.

10voto

jchook Punkte 5914

Die kontextbezogenste Beschreibung von JavaScript ist die Automatische Semikoloneinfügung die ich gefunden habe, stammt aus einem Buch über Crafting Interpreters .

Die "automatische Semikoloneinfügung" von JavaScript ist eine merkwürdige Regel. Während andere Sprachen davon ausgehen, dass die meisten Zeilenumbrüche sinnvoll sind und nur einige wenige in mehrzeiligen Anweisungen ignoriert werden sollten, nimmt JS das Gegenteil an. Es behandelt alle Zeilenumbrüche als bedeutungslose Leerzeichen, es sei denn, es tritt ein Parse-Fehler auf. Wenn dies der Fall ist, geht es zurück und versucht, den vorherigen Zeilenumbruch in ein Semikolon zu verwandeln, um etwas grammatikalisch Gültiges zu erhalten.

Er fährt fort, es so zu beschreiben, wie Sie es tun würden Code-Geruch .

Diese Design-Notiz würde sich in eine Design-Debatte verwandeln, wenn ich bis ins kleinste Detail darauf eingehen würde, wie das überhaupt funktioniert, geschweige denn auf all die verschiedenen Arten, wie das eine schlechte Idee ist. Es ist ein Durcheinander. JavaScript ist die einzige Sprache, die ich kenne, in der viele Styleguides explizite Semikolons nach jeder Anweisung verlangen, obwohl die Sprache es theoretisch erlaubt, sie wegzulassen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X