Lexikalische Grammatik
Diese Seite beschreibt die lexikalische Grammatik von JavaScript. JavaScript-Quelltext ist zunächst nur eine Folge von Zeichen. Damit der Interpreter ihn verstehen kann, muss diese Zeichenfolge in eine stärker strukturierte Darstellung geparst werden. Der erste Schritt des Parsens heißt lexikalische Analyse: Der Text wird von links nach rechts gelesen und in eine Folge einzelner, atomarer Eingabeelemente umgewandelt. Einige Eingabeelemente sind für den Interpreter bedeutungslos und werden nach diesem Schritt entfernt. Dazu gehören Leerraumzeichen und Kommentare. Die übrigen Elemente, darunter Bezeichner, Schlüsselwörter, Literale und Interpunktionszeichen (hauptsächlich Operatoren), werden für die weitere Syntaxanalyse verwendet. Zeilenabschlusszeichen und mehrzeilige Kommentare sind für die Syntax ebenfalls bedeutungslos. Sie steuern jedoch die automatische Semikolon-Einfügung, durch die bestimmte ungültige Tokenfolgen gültig werden.
Formatsteuerzeichen
Formatsteuerzeichen haben keine sichtbare Darstellung, dienen aber dazu, die Interpretation des Textes zu steuern.
| Codepunkt | Name | Abkürzung | Beschreibung |
|---|---|---|---|
| U+200C | Zero Width Non-Joiner | <ZWNJ> | Wird zwischen Zeichen gesetzt, um in bestimmten Sprachen zu verhindern, dass sie zu Ligaturen verbunden werden (Wikipedia). |
| U+200D | Zero Width Joiner | <ZWJ> | Wird zwischen Zeichen gesetzt, die normalerweise nicht verbunden wären, damit sie in bestimmten Sprachen in ihrer verbundenen Form dargestellt werden (Wikipedia). |
| U+FEFF | Byte Order Mark | <BOM> | Wird am Anfang eines Skripts verwendet, um es als Unicode zu kennzeichnen und die Erkennung der Textkodierung und Byte-Reihenfolge zu ermöglichen (Wikipedia). |
Im JavaScript-Quelltext werden <ZWNJ> und <ZWJ> als Bestandteile von Bezeichnern behandelt. <BOM> wird dagegen als Leerraumzeichen behandelt; wenn es nicht am Textanfang steht, heißt es auch Zero-Width No-Break Space (<ZWNBSP>).
Leerraumzeichen
Leerraumzeichen verbessern die Lesbarkeit des Quelltexts und trennen Tokens voneinander. Für die Funktion des Codes sind sie normalerweise nicht erforderlich. Häufig werden Minifizierungswerkzeuge eingesetzt, um Leerraumzeichen zu entfernen und so die zu übertragende Datenmenge zu verringern.
| Codepunkt | Name | Abkürzung | Beschreibung | Escape-Sequenz |
|---|---|---|---|---|
| U+0009 | Character Tabulation | <TAB> | Horizontaler Tabulator | \t |
| U+000B | Line Tabulation | <VT> | Vertikaler Tabulator | \v |
| U+000C | Form Feed | <FF> | Steuerzeichen für einen Seitenumbruch (Wikipedia). | \f |
| U+0020 | Space | <SP> | Normales Leerzeichen | |
| U+00A0 | No-Break Space | <NBSP> | Normales Leerzeichen, an dem jedoch kein Zeilenumbruch erfolgen darf | |
| U+FEFF | Zero-Width No-Break Space | <ZWNBSP> | Wenn der BOM-Marker nicht am Anfang eines Skripts steht, ist er ein normales Leerraumzeichen. | |
| Sonstige | Weitere Unicode-Leerzeichen | <USP> | Zeichen der allgemeinen Kategorie „Space_Separator“ |
Hinweis: Von den Zeichen mit der Eigenschaft „White_Space“, die nicht zur allgemeinen Kategorie „Space_Separator“ gehören, werden U+0009, U+000B und U+000C in JavaScript dennoch als Leerraumzeichen behandelt. U+0085 NEXT LINE hat keine besondere Rolle; die übrigen bilden die Menge der Zeilenabschlusszeichen.
Hinweis:
Änderungen am Unicode-Standard, den die JavaScript-Engine verwendet, können das Verhalten von Programmen beeinflussen. Beispielsweise wurde mit ES2016 der referenzierte Unicode-Standard von Version 5.1 auf 8.0.0 aktualisiert. Dadurch wechselte U+180E MONGOLIAN VOWEL SEPARATOR von der Kategorie „Space_Separator“ in die Kategorie „Format (Cf)“ und galt nicht mehr als Leerraumzeichen. Infolgedessen änderte sich das Ergebnis von "\u180E".trim().length von 0 auf 1.
Zeilenabschlusszeichen
Neben Leerraumzeichen verbessern auch Zeilenabschlusszeichen die Lesbarkeit des Quelltexts. In manchen Fällen können Zeilenabschlusszeichen jedoch die Ausführung von JavaScript-Code beeinflussen, da sie an einigen Stellen nicht zulässig sind. Sie wirken sich außerdem auf die automatische Semikolon-Einfügung aus.
Außerhalb der lexikalischen Grammatik werden Leerraumzeichen und Zeilenabschlusszeichen häufig zusammengefasst. Beispielsweise entfernt String.prototype.trim() alle Leerraum- und Zeilenabschlusszeichen am Anfang und Ende einer Zeichenfolge. Die \s-Zeichenklassen-Escape-Sequenz in regulären Ausdrücken erfasst sämtliche Leerraum- und Zeilenabschlusszeichen.
In ECMAScript werden nur die folgenden Unicode-Codepunkte als Zeilenabschlusszeichen behandelt. Andere Zeichen für Zeilenumbrüche werden als Leerraumzeichen behandelt (beispielsweise gilt Next Line, NEL, U+0085 als Leerraumzeichen).
| Codepunkt | Name | Abkürzung | Beschreibung | Escape-Sequenz |
|---|---|---|---|---|
| U+000A | Line Feed | <LF> | Zeichen für eine neue Zeile auf UNIX-Systemen. | \n |
| U+000D | Carriage Return | <CR> | Zeichen für eine neue Zeile auf Commodore- und frühen Mac-Systemen. | \r |
| U+2028 | Line Separator | <LS> | Wikipedia | |
| U+2029 | Paragraph Separator | <PS> | Wikipedia |
Kommentare
Mit Kommentaren können Sie JavaScript-Code um Hinweise, Anmerkungen, Vorschläge oder Warnungen ergänzen. Dadurch lässt sich der Code leichter lesen und verstehen. Kommentare können auch Code deaktivieren und so dessen Ausführung verhindern – ein nützliches Werkzeug bei der Fehlersuche.
In JavaScript gibt es seit Langem zwei Möglichkeiten, Code zu kommentieren: Zeilenkommentare und Blockkommentare. Darüber hinaus gibt es eine spezielle Syntax für Hashbang-Kommentare.
Zeilenkommentare
Die erste Möglichkeit ist der Kommentar mit //. Der gesamte darauf folgende Text derselben Zeile wird dadurch zum Kommentar. Zum Beispiel:
function comment() {
// This is a one line JavaScript comment
console.log("Hello world!");
}
comment();
Blockkommentare
Die zweite Möglichkeit ist die deutlich flexiblere Schreibweise /* */.
Sie können sie beispielsweise in einer einzelnen Zeile verwenden:
function comment() {
/* This is a one line JavaScript comment */
console.log("Hello world!");
}
comment();
Sie können damit auch mehrzeilige Kommentare erstellen:
function comment() {
/* This comment spans multiple lines. Notice
that we don't need to end the comment until we're done. */
console.log("Hello world!");
}
comment();
Ebenso können Sie sie mitten in einer Zeile verwenden. Da der Code dadurch schwerer lesbar werden kann, sollten Sie diese Möglichkeit jedoch mit Bedacht einsetzen:
function comment(x) {
console.log("Hello " + x /* insert the value of x */ + " !");
}
comment("world");
Außerdem können Sie Code deaktivieren, indem Sie ihn in einen Kommentar einschließen:
function comment() {
/* console.log("Hello world!"); */
}
comment();
In diesem Fall wird console.log() nie aufgerufen, da der Aufruf innerhalb eines Kommentars steht. Auf diese Weise lassen sich beliebig viele Codezeilen deaktivieren.
Blockkommentare, die mindestens ein Zeilenabschlusszeichen enthalten, verhalten sich bei der automatischen Semikolon-Einfügung wie Zeilenabschlusszeichen.
Hashbang-Kommentare
Es gibt eine spezielle dritte Kommentarsyntax: den Hashbang-Kommentar. Ein Hashbang-Kommentar verhält sich genau wie ein einzeiliger Kommentar mit //, beginnt aber mit #! und ist nur unmittelbar am Anfang eines Skripts oder Moduls gültig. Vor #! darf keinerlei Leerraum stehen. Der Kommentar umfasst alle Zeichen nach #! bis zum Ende der ersten Zeile; nur ein solcher Kommentar ist zulässig.
Hashbang-Kommentare in JavaScript ähneln Shebangs unter Unix. Diese geben den Pfad zu einem bestimmten JavaScript-Interpreter an, mit dem das Skript ausgeführt werden soll. Bevor Hashbang-Kommentare standardisiert wurden, waren sie in Umgebungen außerhalb des Browsers wie Node.js bereits de facto implementiert. Dort wurden sie aus dem Quelltext entfernt, bevor dieser an die Engine übergeben wurde. Ein Beispiel:
#!/usr/bin/env node
console.log("Hello world");
Der JavaScript-Interpreter behandelt den Hashbang als normalen Kommentar. Nur für die Shell hat er eine besondere Bedeutung, wenn das Skript direkt in einer Shell ausgeführt wird.
Warnung: Wenn Skripte direkt in einer Shell-Umgebung ausführbar sein sollen, kodieren Sie sie in UTF-8 ohne BOM. Eine BOM verursacht bei Code, der im Browser ausgeführt wird, zwar keine Probleme – sie wird bei der UTF-8-Dekodierung entfernt, bevor der Quelltext analysiert wird –, aber eine Unix-/Linux-Shell erkennt den Hashbang nicht, wenn ihm ein BOM-Zeichen vorangestellt ist.
Verwenden Sie die Kommentarschreibweise #! ausschließlich, um einen JavaScript-Interpreter anzugeben. Verwenden Sie in allen anderen Fällen einen Kommentar mit // oder einen mehrzeiligen Kommentar.
Bezeichner
Ein Bezeichner verknüpft einen Wert mit einem Namen. Bezeichner können an verschiedenen Stellen verwendet werden:
const decl = 1; // Variable declaration (may also be `let` or `var`)
function fn() {} // Function declaration
const obj = { key: "value" }; // Object keys
// Class declaration
class C {
#priv = "value"; // Private field
}
lbl: console.log(1); // Label
In JavaScript bestehen Bezeichner häufig aus alphanumerischen Zeichen, Unterstrichen (_) und Dollarzeichen ($). Sie dürfen nicht mit einer Ziffer beginnen. JavaScript-Bezeichner sind jedoch nicht auf ASCII beschränkt – auch viele Unicode-Codepunkte sind zulässig. Genauer gesagt:
- Als erstes Zeichen sind alle Zeichen der Kategorie ID_Start sowie
_und$zulässig. - Nach dem ersten Zeichen können Sie alle Zeichen der Kategorie ID_Continue verwenden. Dazu gehören U+200C (ZWNJ) und U+200D (ZWJ).
Hinweis:
Falls Sie aus irgendeinem Grund JavaScript-Quelltext selbst parsen müssen, gehen Sie nicht davon aus, dass alle Bezeichner dem Muster /[A-Za-z_$][\w$]*/ folgen, also nur ASCII-Zeichen enthalten! Der zulässige Bereich von Bezeichnern lässt sich durch den regulären Ausdruck /[$_\p{ID_Start}][$\p{ID_Continue}]*/u beschreiben (ohne Unicode-Escape-Sequenzen).
Darüber hinaus erlaubt JavaScript in Bezeichnern Unicode-Escape-Sequenzen der Form \u0000 oder \u{000000}. Sie kodieren denselben Zeichenfolgenwert wie die entsprechenden Unicode-Zeichen. Beispielsweise sind 你好 und \u4f60\u597d derselbe Bezeichner:
const 你好 = "Hello";
console.log(\u4f60\u597d); // Hello
Nicht überall ist der gesamte Bereich zulässiger Bezeichner erlaubt. Bestimmte Syntaxformen, etwa Funktionsdeklarationen, Funktionsausdrücke und Variablendeklarationen, erfordern Bezeichnernamen, die keine reservierten Wörter sind.
function import() {} // Illegal: import is a reserved word.
Insbesondere bei privaten Elementen und Objekteigenschaften sind reservierte Wörter zulässig.
const obj = { import: "value" }; // Legal despite `import` being reserved
class C {
#import = "value";
}
Schlüsselwörter
Schlüsselwörter sind Tokens, die wie Bezeichner aussehen, in JavaScript aber eine besondere Bedeutung haben. Beispielsweise zeigt das Schlüsselwort async vor einer Funktionsdeklaration an, dass die Funktion asynchron ist.
Einige Schlüsselwörter sind reserviert. Das bedeutet, dass sie beispielsweise in Variablen- oder Funktionsdeklarationen nicht als Bezeichner verwendet werden können. Sie werden häufig reservierte Wörter genannt. Eine Liste dieser reservierten Wörter finden Sie weiter unten. Nicht alle Schlüsselwörter sind reserviert: async kann beispielsweise überall als Bezeichner verwendet werden. Andere Schlüsselwörter sind nur kontextabhängig reserviert: await ist beispielsweise nur im Rumpf einer asynchronen Funktion reserviert, während let nur in Code im Strict Mode oder in const- und let-Deklarationen reserviert ist.
Bezeichner werden stets anhand ihres Zeichenfolgenwerts verglichen. Escape-Sequenzen werden daher interpretiert. Beispielsweise liegt hier weiterhin ein Syntaxfehler vor:
const els\u{65} = 1;
// `els\u{65}` encodes the same identifier as `else`
Reservierte Wörter
Diese Schlüsselwörter können nirgendwo im JavaScript-Quelltext als Bezeichner für Variablen, Funktionen, Klassen usw. verwendet werden.
breakcasecatchclassconstcontinuedebuggerdefaultdeletedoelseexportextendsfalsefinallyforfunctionifimportininstanceofnewnullreturnsuperswitchthisthrowtruetrytypeofvarvoidwhilewith
Die folgenden Wörter sind nur in Code im Strict Mode reserviert:
let(auch inconst-,let- und Klassendeklarationen reserviert)staticyield(auch im Rumpf von Generatorfunktionen reserviert)
Das folgende Wort ist nur in Modulcode oder im Rumpf asynchroner Funktionen reserviert:
Für die Zukunft reservierte Wörter
Die folgenden Wörter sind in der ECMAScript-Spezifikation als künftige Schlüsselwörter reserviert. Derzeit haben sie keine besondere Funktion, könnten aber künftig eine erhalten. Deshalb können sie nicht als Bezeichner verwendet werden.
Dieses Wort ist immer reserviert:
enum
Die folgenden Wörter sind nur in Code im Strict Mode reserviert:
implementsinterfacepackageprivateprotectedpublic
In älteren Standards für die Zukunft reservierte Wörter
Die folgenden Wörter waren in älteren ECMAScript-Spezifikationen (ECMAScript 1 bis 3) als künftige Schlüsselwörter reserviert.
abstractbooleanbytechardoublefinalfloatgotointlongnativeshortsynchronizedthrowstransientvolatile
Bezeichner mit besonderer Bedeutung
Einige Bezeichner haben in bestimmten Kontexten eine besondere Bedeutung, ohne reservierte Wörter zu sein. Dazu gehören:
arguments(kein Schlüsselwort, darf im Strict Mode aber nicht als Bezeichner deklariert werden)as(import * as ns from "mod")asynceval(kein Schlüsselwort, darf im Strict Mode aber nicht als Bezeichner deklariert werden)from(import x from "mod")getofset
Literale
Hinweis: Dieser Abschnitt behandelt Literale, die atomare Tokens sind. Objektliterale und Array-Literale sind Ausdrücke, die aus einer Folge von Tokens bestehen.
Null-Literal
Weitere Informationen finden Sie auch unter null.
null
Boolean-Literal
Weitere Informationen finden Sie auch unter Boolean-Typ.
true
false
Numerische Literale
Die Typen Number und BigInt verwenden numerische Literale.
Dezimal
1234567890
42
Dezimale Literale können mit einer Null (0) beginnen, auf die eine weitere Dezimalziffer folgt. Sind jedoch alle Ziffern nach der führenden 0 kleiner als 8, wird die Zahl als Oktalzahl interpretiert. Diese Syntax gilt als veraltet. Zahlenliterale mit vorangestellter 0 verursachen im Strict Mode einen Syntaxfehler – unabhängig davon, ob sie als Oktal- oder Dezimalzahl interpretiert würden. Verwenden Sie stattdessen das Präfix 0o.
0888 // 888 parsed as decimal
0777 // parsed as octal, 511 in decimal
Exponentialschreibweise
Ein dezimales Exponentialliteral hat das Format beN. Dabei ist b eine Basiszahl (Ganzzahl oder Gleitkommazahl), gefolgt von E oder e als Trennzeichen beziehungsweise Exponentenkennzeichen. N ist der Exponent – eine vorzeichenbehaftete Ganzzahl.
0e-5 // 0
0e+5 // 0
5e1 // 50
175e-2 // 1.75
1e3 // 1000
1e-3 // 0.001
1E3 // 1000
Binär
Die Syntax für Binärzahlen beginnt mit einer Null, gefolgt vom lateinischen Buchstaben „B“ in Klein- oder Großschreibung (0b oder 0B). Jedes Zeichen nach 0b, das weder 0 noch 1 ist, beendet die Literalsequenz.
0b10000000000000000000000000000000 // 2147483648
0b01111111100000000000000000000000 // 2139095040
0B00000000011111111111111111111111 // 8388607
Oktal
Die Syntax für Oktalzahlen beginnt mit einer Null, gefolgt vom lateinischen Buchstaben „O“ in Klein- oder Großschreibung (0o oder 0O). Jedes Zeichen nach 0o, das außerhalb des Bereichs (01234567) liegt, beendet die Literalsequenz.
0O755 // 493
0o644 // 420
Hexadezimal
Die Syntax für Hexadezimalzahlen beginnt mit einer Null, gefolgt vom lateinischen Buchstaben „X“ in Klein- oder Großschreibung (0x oder 0X). Jedes Zeichen nach 0x, das außerhalb des Bereichs (0123456789ABCDEF) liegt, beendet die Literalsequenz.
0xFFFFFFFFFFFFF // 4503599627370495
0xabcdef123456 // 188900967593046
0XA // 10
BigInt-Literal
Der Typ BigInt ist ein numerischer primitiver Typ in JavaScript, der Ganzzahlen mit beliebiger Genauigkeit darstellen kann. BigInt-Literale werden gebildet, indem an eine Ganzzahl ein n angehängt wird.
123456789123456789n // 123456789123456789
0o777777777777n // 68719476735
0x123456789ABCDEFn // 81985529216486895
0b11101001010101010101n // 955733
BigInt-Literale dürfen nicht mit 0 beginnen, um Verwechslungen mit veralteten Oktalliteralen zu vermeiden.
0755n; // SyntaxError: invalid BigInt syntax
Verwenden Sie für oktale BigInt-Zahlen immer eine Null, gefolgt vom Buchstaben „o“ (groß- oder kleingeschrieben):
0o755n;
Weitere Informationen zu BigInt finden Sie unter JavaScript-Datenstrukturen.
Numerische Trennzeichen
Um numerische Literale besser lesbar zu machen, können Unterstriche (_, U+005F) als Trennzeichen verwendet werden:
1_000_000_000_000
1_050.95
0b1010_0001_1000_0101
0o2_2_5_6
0xA0_B0_C0
1_000_000_000_000_000_000_000n
Beachten Sie dabei folgende Einschränkungen:
// More than one underscore in a row is not allowed
100__000; // SyntaxError
// Not allowed at the end of numeric literals
100_; // SyntaxError
// Can not be used after leading 0
0_1; // SyntaxError
Zeichenfolgenliterale
Ein Zeichenfolgenliteral besteht aus null oder mehr Unicode-Codepunkten, die in einfache oder doppelte Anführungszeichen eingeschlossen sind. Unicode-Codepunkte können auch durch Escape-Sequenzen dargestellt werden. Alle Codepunkte dürfen direkt in einem Zeichenfolgenliteral vorkommen, mit Ausnahme der folgenden:
- U+005C \ (umgekehrter Schrägstrich)
- U+000D <CR>
- U+000A <LF>
- Anführungszeichen derselben Art, mit der das Zeichenfolgenliteral beginnt
Jeder Codepunkt kann in Form einer Escape-Sequenz vorkommen. Zeichenfolgenliterale ergeben ECMAScript-String-Werte. Bei der Erzeugung dieser String-Werte werden Unicode-Codepunkte in UTF-16 kodiert.
'foo'
"bar"
Die folgenden Unterabschnitte beschreiben verschiedene Escape-Sequenzen (ein \, gefolgt von einem oder mehreren Zeichen), die in Zeichenfolgenliteralen verfügbar sind. Jede unten nicht aufgeführte Escape-Sequenz wird zu einem „Identity Escape“, der dem Codepunkt des Zeichens selbst entspricht. Beispielsweise ist \z dasselbe wie z. Eine veraltete Syntax für oktale Escape-Sequenzen wird auf der Seite Veraltete und obsolete Funktionen beschrieben. Viele dieser Escape-Sequenzen sind auch in regulären Ausdrücken gültig – siehe Zeichen-Escape.
Escape-Sequenzen
Sonderzeichen können mit Escape-Sequenzen kodiert werden:
| Escape-Sequenz | Unicode-Codepunkt |
|---|---|
\0 |
Nullzeichen (U+0000 NULL) |
\' |
Einfaches Anführungszeichen (U+0027 APOSTROPHE) |
\" |
Doppeltes Anführungszeichen (U+0022 QUOTATION MARK) |
\\ |
Umgekehrter Schrägstrich (U+005C REVERSE SOLIDUS) |
\n |
Zeilenumbruch (U+000A LINE FEED; LF) |
\r |
Wagenrücklauf (U+000D CARRIAGE RETURN; CR) |
\v |
Vertikaler Tabulator (U+000B LINE TABULATION) |
\t |
Tabulator (U+0009 CHARACTER TABULATION) |
\b |
Rückschritt (U+0008 BACKSPACE) |
\f |
Seitenvorschub (U+000C FORM FEED) |
\, gefolgt von einem Zeilenabschlusszeichen |
Leere Zeichenfolge |
Die letzte Escape-Sequenz – ein \, gefolgt von einem Zeilenabschlusszeichen – ist nützlich, um ein Zeichenfolgenliteral über mehrere Zeilen zu verteilen, ohne seine Bedeutung zu ändern.
const longString =
"This is a very long string which needs \
to wrap across multiple lines because \
otherwise my code is unreadable.";
Stellen Sie sicher, dass nach dem umgekehrten Schrägstrich kein Leerzeichen oder anderes Zeichen steht (außer einem Zeilenumbruch). Andernfalls funktioniert dies nicht. Wenn die nächste Zeile eingerückt ist, sind die zusätzlichen Leerzeichen auch im Wert der Zeichenfolge enthalten.
Sie können auch den Operator + verwenden, um mehrere Zeichenfolgen aneinanderzuhängen:
const longString =
"This is a very long string which needs " +
"to wrap across multiple lines because " +
"otherwise my code is unreadable.";
Beide beschriebenen Methoden ergeben identische Zeichenfolgen.
Hexadezimale Escape-Sequenzen
Hexadezimale Escape-Sequenzen bestehen aus \x, gefolgt von genau zwei hexadezimalen Ziffern. Diese stellen eine Codeeinheit oder einen Codepunkt im Bereich von 0x0000 bis 0x00FF dar.
"\xA9"; // "©"
Unicode-Escape-Sequenzen
Eine Unicode-Escape-Sequenz besteht aus genau vier hexadezimalen Ziffern nach \u. Sie stellt eine Codeeinheit in der UTF-16-Kodierung dar. Bei Codepunkten von U+0000 bis U+FFFF entspricht die Codeeinheit dem Codepunkt. Codepunkte von U+10000 bis U+10FFFF benötigen zwei Escape-Sequenzen, die die beiden zur Kodierung des Zeichens verwendeten Codeeinheiten darstellen (ein Surrogatpaar). Das Surrogatpaar ist nicht mit dem Codepunkt identisch.
Siehe auch String.fromCharCode() und String.prototype.charCodeAt().
"\u00A9"; // "©" (U+A9)
Unicode-Codepunkt-Escape-Sequenzen
Eine Unicode-Codepunkt-Escape-Sequenz besteht aus \u{, gefolgt von einem hexadezimal angegebenen Codepunkt und }. Der Wert der hexadezimalen Ziffern muss einschließlich der Grenzen zwischen 0 und 0x10FFFF liegen. Codepunkte im Bereich U+10000 bis U+10FFFF müssen nicht als Surrogatpaar dargestellt werden.
Siehe auch String.fromCodePoint() und String.prototype.codePointAt().
"\u{2F804}"; // CJK COMPATIBILITY IDEOGRAPH-2F804 (U+2F804)
// the same character represented as a surrogate pair
"\uD87E\uDC04";
Literale regulärer Ausdrücke
Literale regulärer Ausdrücke werden von zwei Schrägstrichen (/) eingeschlossen. Der Lexer liest alle Zeichen bis zum nächsten nicht mit einer Escape-Sequenz versehenen Schrägstrich oder bis zum Zeilenende, es sei denn, der Schrägstrich steht innerhalb einer Zeichenklasse ([]). Nach dem abschließenden Schrägstrich können bestimmte Zeichen stehen (nämlich solche, die Bestandteile von Bezeichnern sein können); sie kennzeichnen Flags.
Die lexikalische Grammatik ist sehr nachsichtig: Nicht jedes Literal eines regulären Ausdrucks, das als einzelnes Token erkannt wird, ist ein gültiger regulärer Ausdruck.
Weitere Informationen finden Sie auch unter RegExp.
/ab+c/g;
/[/]/;
Ein Literal eines regulären Ausdrucks kann nicht mit zwei Schrägstrichen (//) beginnen, da dies einen Zeilenkommentar einleiten würde. Verwenden Sie /(?:)/, um einen leeren regulären Ausdruck anzugeben.
Template-Literale
Ein Template-Literal besteht aus mehreren Tokens: `xxx${ (Template-Anfang), }xxx${ (Template-Mittelteil) und }xxx` (Template-Ende) sind jeweils eigenständige Tokens. Dazwischen kann ein beliebiger Ausdruck stehen.
Weitere Informationen finden Sie auch unter Template-Literale.
`string text`;
`string text line 1
string text line 2`;
`string text ${expression} string text`;
tag`string text ${expression} string text`;
Automatische Semikolon-Einfügung
Die Syntaxdefinitionen einiger JavaScript-Anweisungen verlangen ein Semikolon (;) am Ende. Dazu gehören:
var,let,const,using,await using- Ausdrucksanweisungen
do...whilecontinue,break,return,throwdebugger- Deklarationen von Klassenfeldern (öffentlich oder privat)
import,export
Um die Sprache zugänglicher und komfortabler zu machen, kann JavaScript beim Verarbeiten des Tokenstroms automatisch Semikolons einfügen. Dadurch können einige ungültige Tokenfolgen zu gültiger Syntax „korrigiert“ werden. Dieser Schritt erfolgt, nachdem der Programmtext gemäß der lexikalischen Grammatik in Tokens zerlegt wurde. In drei Fällen werden Semikolons automatisch eingefügt:
1. Wenn ein Token auftritt, das die Grammatik nicht zulässt, und es vom vorherigen Token durch mindestens ein Zeilenabschlusszeichen getrennt ist (einschließlich eines Blockkommentars mit mindestens einem Zeilenabschlusszeichen), oder wenn das Token } ist, wird vor dem Token ein Semikolon eingefügt.
{ 1
2 } 3
// is transformed by ASI into:
{ 1
;2 ;} 3;
// Which is valid grammar encoding three statements,
// each consisting of a number literal
Die schließende Klammer ) von do...while wird durch diese Regel ebenfalls als Sonderfall behandelt.
do {
// …
} while (condition) /* ; */ // ASI here
const a = 1
Es werden jedoch keine Semikolons eingefügt, wenn das Semikolon dadurch zum Trennzeichen im Kopf einer for-Anweisung würde.
for (
let a = 1 // No ASI here
a < 10 // No ASI here
a++
) {}
Automatisch eingefügte Semikolons bilden auch niemals leere Anweisungen. Im folgenden Code wäre beispielsweise ein Semikolon nach ) gültig: Der Rumpf der if-Anweisung wäre dann eine leere Anweisung, und die const-Deklaration wäre eine separate Anweisung. Da automatisch eingefügte Semikolons jedoch keine leeren Anweisungen bilden dürfen, würde die Deklaration zum Rumpf der if-Anweisung. Das ist ungültig.
if (Math.random() > 0.5)
const x = 1 // SyntaxError: Unexpected token 'const'
2. Wenn das Ende des Tokenstroms erreicht ist und der Parser den Tokenstrom nicht als vollständiges Programm parsen kann, wird am Ende ein Semikolon eingefügt.
const a = 1 /* ; */ // ASI here
Diese Regel ergänzt die vorherige für den Fall, dass kein „unzulässiges Token“ vorhanden ist, sondern lediglich das Ende des Eingabestroms erreicht wurde.
3. Wenn die Grammatik an einer bestimmten Stelle Zeilenabschlusszeichen verbietet, dort aber eines vorkommt, wird ein Semikolon eingefügt. Zu diesen Stellen gehören:
expr <here> ++,expr <here> --continue <here> lblbreak <here> lblreturn <here> exprthrow <here> expryield <here> expryield <here> * expr(param) <here> => {}async <here> function,async <here> prop(),async <here> function*,async <here> *prop(),async <here> (param) <here> => {}using <here> id,await <here> using <here> id
Hier wird ++ nicht als Postfix-Operator für die Variable b behandelt, weil zwischen b und ++ ein Zeilenabschlusszeichen steht.
a = b
++c
// is transformed by ASI into
a = b;
++c;
Hier gibt die return-Anweisung undefined zurück, und a + b wird zu einer unerreichbaren Anweisung.
return
a + b
// is transformed by ASI into
return;
a + b;
Beachten Sie, dass die automatische Semikolon-Einfügung (ASI) nur ausgelöst wird, wenn ein Zeilenumbruch Tokens trennt, die andernfalls ungültige Syntax ergeben würden. Kann das nächste Token als Teil einer gültigen Struktur geparst werden, wird kein Semikolon eingefügt. Zum Beispiel:
const a = 1
(1).toString()
const b = 1
[1, 2, 3].forEach(console.log)
Da () als Funktionsaufruf interpretiert werden kann, löst es normalerweise keine automatische Semikolon-Einfügung aus. Ebenso kann [] ein Eigenschaftszugriff sein. Der obige Code entspricht:
const a = 1(1).toString();
const b = 1[1, 2, 3].forEach(console.log);
Das ist zufällig gültige Syntax. 1[1, 2, 3] ist ein Eigenschaftszugriff mit einem durch Kommas verknüpften Ausdruck. Beim Ausführen des Codes erhalten Sie daher Fehlermeldungen wie „1 is not a function“ und „Cannot read properties of undefined (reading 'forEach')“.
Innerhalb von Klassen können auch Klassenfelder und Generatormethoden eine Fehlerquelle sein.
class A {
a = 1
*gen() {}
}
Der Code wird wie folgt interpretiert:
class A {
a = 1 * gen() {}
}
Daher tritt bei { ein Syntaxfehler auf.
Wenn Sie einen Stil ohne Semikolons durchsetzen möchten, helfen Ihnen die folgenden Faustregeln beim Umgang mit ASI:
-
Schreiben Sie die Postfix-Operatoren
++und--in dieselbe Zeile wie ihre Operanden.jsconst a = b ++ console.log(a) // ReferenceError: Invalid left-hand side expression in prefix operationjsconst a = b++ console.log(a) -
Der Ausdruck nach
return,throwoderyieldsollte in derselben Zeile wie das Schlüsselwort stehen.jsfunction foo() { return 1 + 1 // Returns undefined; 1 + 1 is ignored }jsfunction foo() { return 1 + 1 } function foo() { return ( 1 + 1 ) } -
Ebenso sollte der Label-Bezeichner nach
breakodercontinuein derselben Zeile wie das Schlüsselwort stehen.jsouterBlock: { innerBlock: { break outerBlock // SyntaxError: Illegal break statement } }jsouterBlock: { innerBlock: { break outerBlock } } -
Das
=>einer Pfeilfunktion sollte in derselben Zeile stehen wie das Ende ihrer Parameterliste.jsconst foo = (a, b) => a + bjsconst foo = (a, b) => a + b -
Auf
asyncbei asynchronen Funktionen, Methoden usw. darf nicht unmittelbar ein Zeilenabschlusszeichen folgen.jsasync function foo() {}jsasync function foo() {} -
Das Schlüsselwort
usinginusing- undawait using-Anweisungen sollte in derselben Zeile stehen wie der erste damit deklarierte Bezeichner.jsusing resource = acquireResource()jsusing resource = acquireResource() -
Wenn eine Zeile mit
(,[,`,+,-oder/(wie bei Literalen regulärer Ausdrücke) beginnt, stellen Sie ihr ein Semikolon voran oder beenden Sie die vorherige Zeile mit einem Semikolon.js// The () may be merged with the previous line as a function call (() => { // … })() // The [ may be merged with the previous line as a property access [1, 2, 3].forEach(console.log) // The ` may be merged with the previous line as a tagged template literal `string text ${data}`.match(pattern).forEach(console.log) // The + may be merged with the previous line as a binary + expression +a.toString() // The - may be merged with the previous line as a binary - expression -a.toString() // The / may be merged with the previous line as a division expression /pattern/.exec(str).forEach(console.log)js;(() => { // … })() ;[1, 2, 3].forEach(console.log) ;`string text ${data}`.match(pattern).forEach(console.log) ;+a.toString() ;-a.toString() ;/pattern/.exec(str).forEach(console.log) -
Klassenfelder sollten vorzugsweise immer mit einem Semikolon abgeschlossen werden. Zusätzlich zur vorherigen Regel (die auch eine Felddeklaration vor einer berechneten Eigenschaft umfasst, da Letztere mit
[beginnt) sind Semikolons auch zwischen einer Felddeklaration und einer Generatormethode erforderlich.jsclass A { a = 1 [b] = 2 *gen() {} // Seen as a = 1[b] = 2 * gen() {} }jsclass A { a = 1; [b] = 2; *gen() {} }
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> |
Browser-Kompatibilität
Siehe auch
- Leitfaden Grammatik und Typen
- Kleine Neuerung aus ES6, jetzt in Firefox Aurora und Nightly: Binär- und Oktalzahlen von Jeff Walden (2013)
- JavaScript-Zeichen-Escape-Sequenzen von Mathias Bynens (2011)