JavaScripts Syntax ist ziemlich unkompliziert. Dieses Kapitel beschreibt Dinge, auf die Sie achten sollten.
Dieser Abschnitt gibt Ihnen einen schnellen Eindruck davon, wie JavaScripts Syntax aussieht.
Die folgenden sind fünf grundlegende Arten von Werten:
Hier sind einige Beispiele für grundlegende Syntax:
// Two slashes start single-linecommentsvarx;// declaring a variablex=3+y;// assigning a value to the variable `x`foo(x,y);// calling function `foo` with parameters `x` and `y`obj.bar(3);// calling method `bar` of object `obj`// A conditional statementif(x===0){// Is `x` equal to zero?x=123;}// Defining function `baz` with parameters `a` and `b`functionbaz(a,b){returna+b;}
Beachten Sie die beiden unterschiedlichen Verwendungen von dem Gleichheitszeichen:
=) wird verwendet, um einer Variablen einen Wert zuzuweisen.===) wird verwendet, um zwei Werte zu vergleichen (siehe Gleichheitsoperatoren).Es gibt zwei Arten von Kommentaren
Einzeilige Kommentare über // reichen bis zum Rest der Zeile. Hier ist ein Beispiel:
vara=0;// init
Mehrzeilige Kommentare über /* */ können sich über beliebige Textbereiche erstrecken. Sie können nicht verschachtelt werden. Hier sind zwei Beispiele:
/* temporarily disabledprocessNext(queue);*/function(a/* int */,b/* str */){}
Dieser Abschnitt betrachtet eine wichtige syntaktische Unterscheidung in JavaScript: den Unterschied zwischen Ausdrücken und Anweisungen.
myvar3+xmyfunc('a','b')
Grob gesagt führt eine Anweisung eine Aktion aus. Schleifen und if-Anweisungen sind Beispiele für Anweisungen. Ein Programm ist im Grunde eine Abfolge von Anweisungen.[8]
Wo auch immer JavaScript eine Anweisung erwartet, können Sie auch einen Ausdruck schreiben. Eine solche Anweisung wird als Ausdrucksanweisung bezeichnet. Das Gegenteil gilt nicht: Sie können keine Anweisung schreiben, wo JavaScript einen Ausdruck erwartet. Zum Beispiel kann eine if-Anweisung nicht zum Argument einer Funktion werden.
Der Unterschied zwischen Anweisungen und Ausdrücken wird deutlicher, wenn wir uns Mitglieder der beiden syntaktischen Kategorien ansehen, die ähnlich sind: die if-Anweisung und der ternäre Operator (ein Ausdruck).
Das Folgende ist ein Beispiel für eine if-Anweisung:
varsalutation;if(male){salutation='Mr.';}else{salutation='Mrs.';}
Es gibt eine ähnliche Art von Ausdruck, den ternären Operator. Die vorherigen Anweisungen sind äquivalent zum folgenden Code:
varsalutation=(male?'Mr.':'Mrs.');
Der Code zwischen dem Gleichheitszeichen und dem Semikolon ist ein Ausdruck. Die Klammern sind nicht notwendig, aber ich finde den ternären Operator leichter zu lesen, wenn ich ihn in Klammern setze.
Zwei Arten von Ausdrücken sehen wie Anweisungen aus – sie sind hinsichtlich ihrer syntaktischen Kategorie mehrdeutig:
Objektliterale (Ausdrücke) sehen wie Blöcke (Anweisungen) aus:
{foo:bar(3,5)}
Der vorherige Konstrukt ist entweder ein Objektliteral (Details: Objektliterale) oder ein Block, gefolgt von der Markierung foo:, gefolgt vom Funktionsaufruf bar(3, 5).
Benannte Funktionsausdrücke sehen wie Funktionsdeklarationen (Anweisungen) aus:
functionfoo(){}
Der vorherige Konstrukt ist entweder ein benannter Funktionsausdruck oder eine Funktionsdeklaration. Ersteres erzeugt eine Funktion, letzteres erstellt eine Variable und weist ihr eine Funktion zu (Details zu beiden Arten der Funktionsdefinition: Funktionen definieren).
Um Mehrdeutigkeiten während des Parsens zu vermeiden, lässt JavaScript keine Objektliterale und Funktionsausdrücke als Anweisungen zu. Das heißt, Ausdrucksanweisungen dürfen nicht beginnen mit
functionWenn ein Ausdruck mit einem dieser Token beginnt, kann er nur in einem Ausdruckskontext erscheinen. Sie können diese Anforderung erfüllen, indem Sie beispielsweise Klammern um den Ausdruck setzen. Als Nächstes werden wir uns zwei Beispiele ansehen, bei denen dies notwendig ist.
eval parst sein Argument in einem Anweisungskontext. Sie müssen Klammern um ein Objektliteral setzen, wenn Sie möchten, dass eval ein Objekt zurückgibt:
> eval('{ foo: 123 }')
123
> eval('({ foo: 123 })')
{ foo: 123 }Der folgende Code ist ein sofort aufgerufener Funktionsausdruck (IIFE), eine Funktion, deren Körper sofort ausgeführt wird (was Sie über IIFEs erfahren, lesen Sie in Einführung eines neuen Gültigkeitsbereichs über ein IIFE)
> (function () { return 'abc' }())
'abc'Wenn Sie die Klammern weglassen, erhalten Sie einen Syntaxfehler, da JavaScript eine Funktionsdeklaration sieht, die nicht anonym sein kann.
> function () { return 'abc' }()
SyntaxError: function statement requires a nameWenn Sie einen Namen hinzufügen, erhalten Sie ebenfalls einen Syntaxfehler, da Funktionsdeklarationen nicht sofort aufgerufen werden können.
> function foo() { return 'abc' }()
SyntaxError: Unexpected token )Was auch immer einer Funktionsdeklaration folgt, muss eine legale Anweisung sein und () ist keine.
Für Kontrollflussanweisungen ist der Körper eine einzelne Anweisung. Hier sind zwei Beispiele:
if(obj!==null)obj.foo();while(x>0)x--;
Allerdings kann jede Anweisung immer durch einen Block ersetzt werden, geschweifte Klammern, die null oder mehr Anweisungen enthalten. Sie können also auch schreiben:
if(obj!==null){obj.foo();}while(x>0){x--;}
Ich bevorzuge die letztere Form der Kontrollflussanweisung. Wenn man sich daran gewöhnt, gibt es keinen Unterschied zwischen Ein- und Mehrfachanweisungskörpern. Das Ergebnis ist, dass Ihr Code konsistenter aussieht und der Wechsel zwischen einer und mehr als einer Anweisung einfacher ist.
In diesem Abschnitt untersuchen wir, wie Semikolons in JavaScript verwendet werden. Die Grundregeln lauten:
Semikolons sind in JavaScript optional. Fehlende Semikolons werden über die sogenannte automatische Semikolon-Einfügung (ASI; siehe Automatische Semikolon-Einfügung) hinzugefügt. Diese Funktion funktioniert jedoch nicht immer wie erwartet, weshalb Sie immer Semikolons einfügen sollten.
Die folgenden Anweisungen werden nicht durch Semikolons beendet, wenn sie mit einem Block enden:
for, while (aber nicht do-while)if, switch, tryHier ist ein Beispiel für while im Vergleich zu do-while
while(a>0){a--;}// no semicolondo{a--;}while(a>0);
Und hier ist ein Beispiel für eine Funktionsdeklaration im Vergleich zu einem Funktionsausdruck. Letzterer wird von einem Semikolon gefolgt, da er innerhalb einer var-Deklaration erscheint (die von einem Semikolon beendet wird)
functionfoo(){// ...}// no semicolonvarfoo=function(){// ...};
Wenn Sie nach einem Block ein Semikolon hinzufügen, erhalten Sie keinen Syntaxfehler, da es als leere Anweisung betrachtet wird (siehe nächster Abschnitt).
Das ist das meiste, was Sie über Semikolons wissen müssen. Wenn Sie immer Semikolons hinzufügen, können Sie wahrscheinlich auskommen, ohne die restlichen Teile dieses Abschnitts zu lesen.
Ein Semikolon allein ist eine leere Anweisung und tut nichts. Leere Anweisungen können überall dort stehen, wo eine Anweisung erwartet wird. Sie sind nützlich in Situationen, in denen eine Anweisung gefordert ist, aber nicht benötigt wird. In solchen Situationen sind normalerweise auch Blöcke erlaubt. Zum Beispiel sind die folgenden beiden Anweisungen äquivalent:
while(processNextItem()>0);while(processNextItem()>0){}
Es wird angenommen, dass die Funktion processNextItem die Anzahl der verbleibenden Elemente zurückgibt. Das folgende Programm, das aus drei leeren Anweisungen besteht, ist ebenfalls syntaktisch korrekt
;;;Das Ziel der automatischen Semikolon-Einfügung (ASI) ist es, Semikolons am Ende einer Zeile optional zu machen. Das Bild, das der Begriff automatische Semikolon-Einfügung hervorruft, ist, dass der JavaScript-Parser Semikolons für Sie einfügt (intern werden die Dinge normalerweise anders gehandhabt).
Anders ausgedrückt, ASI hilft dem Parser zu bestimmen, wann eine Anweisung endet. Normalerweise endet sie mit einem Semikolon. ASI schreibt vor, dass eine Anweisung auch endet, wenn
Der folgende Code enthält einen Zeilenumbruch gefolgt von einem ungültigen Token:
if(a<0)a=0console.log(a)
Das Token console ist nach 0 ungültig und löst ASI aus.
if(a<0)a=0;console.log(a);
functionadd(a,b){returna+b}
ASI erstellt eine syntaktisch korrekte Version des vorherigen Codes.
functionadd(a,b){returna+b;}
ASI wird auch ausgelöst, wenn nach dem Schlüsselwort return ein Zeilenumbruch steht. Zum Beispiel:
// Don't do thisreturn{name:'John'};
ASI verwandelt das Vorherige in
return;{name:'John'};
Das ist ein leeres Return, gefolgt von einem Block mit der Markierung name vor der Ausdrucksanweisung 'John'. Nach dem Block gibt es eine leere Anweisung.
Manchmal beginnt eine Anweisung in einer neuen Zeile mit einem Token, das als Fortsetzung der vorherigen Anweisung zulässig ist. Dann wird ASI nicht ausgelöst, obwohl es den Anschein hat, als sollte es das. Zum Beispiel:
func()['ul','ol'].forEach(function(t){handleTag(t)})
Die eckigen Klammern in der zweiten Zeile werden als Index in das von func() zurückgegebene Ergebnis interpretiert. Das Komma in den Klammern wird als KommaOperator interpretiert (der in diesem Fall 'ol' zurückgibt; siehe Der Komma-Operator). Daher sieht JavaScript den vorherigen Code so:
func()['ol'].forEach(function(t){handleTag(t)});
Bezeichner werden zum Benennen von Dingen verwendet und erscheinen in verschiedenen syntaktischen Rollen in JavaScript. Zum Beispiel müssen die Namen von Variablen und nicht zitierten Eigenschaftsschlüsseln gültige Bezeichner sein. Bezeichner sind case-sensitiv.
Das erste Zeichen eines Bezeichners ist eines von
$)_)Nachfolgende Zeichen sind
Beispiele für gültige Bezeichner
varε=0.0001;varстрока='';var_tmp;var$foo2;
Auch wenn dies Ihnen ermöglicht, eine Vielzahl von menschlichen Sprachen in JavaScript-Code zu verwenden, empfehle ich, bei Englisch zu bleiben, sowohl für Bezeichner als auch für Kommentare. Das stellt sicher, dass Ihr Code für die größtmögliche Gruppe von Menschen verständlich ist, was wichtig ist, da sich heutzutage viel Code international verbreitet.
Die folgenden Bezeichner sind reservierte Wörter – sie sind Teil der Syntax und können nicht als Variablennamen (einschließlich Funktionsnamen und Parameternamen) verwendet werden:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Die folgenden drei Bezeichner sind keine reservierten Wörter, aber Sie sollten sie so behandeln, als wären sie es.
|
|
|
Schließlich sollten Sie auch die Namen von Standard-Globalvariablen meiden (siehe Kapitel 23). Sie können sie für lokale Variablen verwenden, ohne etwas kaputt zu machen, aber Ihr Code wird trotzdem verwirrend.
Beachten Sie, dass Sie reservierte Wörter als unquotierte Eigenschaftsschlüssel verwenden können (ab ECMAScript 5).
> var obj = { function: 'abc' };
> obj.function
'abc'Die genauen Regeln für Bezeichner können Sie in Mathias Bynens' Blogbeitrag „Gültige JavaScript-Variablennamen“ nachschlagen.
Bei Methodaufrufen ist es wichtig, zwischen dem Punkt für Gleitkommazahlen und dem Punkt für den Methodenaufruf zu unterscheiden. Daher können Sie nicht 1.toString() schreiben; Sie müssen eine der folgenden Alternativen verwenden:
1..toString()1.toString()// space before dot(1).toString()1.0.toString()
ECMAScript 5 hat einen Strikten Modus, der zu saubererem JavaScript führt, mit weniger unsicheren Funktionen, mehr Warnungen und logischerem Verhalten. Der normale (nicht strikte) Modus wird manchmal als „Locker Modus“ bezeichnet.
Sie schalten den Strikten Modus ein, indem Sie die folgende Zeile zuerst in Ihre JavaScript-Datei oder in Ihr <script>-Element schreiben:
'use strict';
Beachten Sie, dass JavaScript-Engines, die ECMAScript 5 nicht unterstützen, die vorherige Anweisung einfach ignorieren, da das Schreiben von Zeichenketten auf diese Weise (als Ausdrucksanweisung; siehe Anweisungen) normalerweise nichts bewirkt.
Sie können den Strikten Modus auch pro Funktion einschalten. Um dies zu tun, schreiben Sie Ihre Funktion wie folgt:
functionfoo(){'use strict';...}
Dies ist praktisch, wenn Sie mit einer Altkodebasis arbeiten, bei der das Einschalten des Strikten Modus überall Dinge kaputt machen kann.
Im Allgemeinen sind die Änderungen, die durch den Strikten Modus ermöglicht werden, alle zum Besseren. Daher wird dringend empfohlen, ihn für neuen Code zu verwenden, den Sie schreiben – schalten Sie ihn einfach am Anfang einer Datei ein. Es gibt jedoch zwei Einschränkungen:
Die folgenden Abschnitte erklären die Funktionen des Strikten Modus im Detail. Sie müssen sie normalerweise nicht kennen, da Sie hauptsächlich mehr Warnungen für Dinge erhalten, die Sie ohnehin nicht tun sollten.
Alle Variablen müssen im Strikten Modus explizit deklariert werden. Dies hilft, Tippfehler zu vermeiden. Im Locker Modus erstellt die Zuweisung an eine nicht deklarierte Variable eine globale Variable:
functionsloppyFunc(){sloppyVar=123;}sloppyFunc();// creates global variable `sloppyVar`console.log(sloppyVar);// 123
Im Strikten Modus wirft die Zuweisung an eine nicht deklarierte Variable eine Ausnahme.
functionstrictFunc(){'use strict';strictVar=123;}strictFunc();// ReferenceError: strictVar is not defined
Der Strikte Modus beschränkt funktionsbezogene Merkmale.
Im Strikten Modus müssen alle Funktionen auf der obersten Ebene eines Gültigkeitsbereichs (globaler Gültigkeitsbereich oder direkt innerhalb einer Funktion) deklariert werden. Das bedeutet, dass Sie keine Funktionsdeklaration innerhalb eines Blocks platzieren können. Wenn Sie dies tun, erhalten Sie eine aussagekräftige SyntaxError. Zum Beispiel sagt V8 Ihnen: „In striktem Code können Funktionen nur auf oberster Ebene oder unmittelbar innerhalb einer anderen Funktion deklariert werden“:
functionstrictFunc(){'use strict';if(true){// SyntaxError:functionnested(){}}}
Das ist ohnehin nichts Nützliches, da die Funktion im Gültigkeitsbereich der umgebenden Funktion erstellt wird, nicht „innerhalb“ des Blocks.
Wenn Sie diese Einschränkung umgehen möchten, können Sie eine Funktion innerhalb eines Blocks über eine Variablendeklaration und einen Funktionsausdruck erstellen.
functionstrictFunc(){'use strict';if(true){// OK:varnested=function(){};}}
Die Regeln für Funktionsparameter sind weniger permissiv: die doppelte Verwendung desselben Parameternamens ist verboten, ebenso wie lokale Variablen, die denselben Namen wie ein Parameter haben.
Das arguments-Objekt ist im Strikten Modus einfacher: die Eigenschaften arguments.callee und arguments.caller wurden entfernt, Sie können der Variablen arguments keine Werte zuweisen, und arguments verfolgt keine Änderungen an Parametern (wenn sich ein Parameter ändert, ändert sich das entsprechende Array-Element nicht mit ihm). Veraltete Funktionen von arguments erklärt die Details.
Im Locker Modus ist der Wert von this in Nicht-Methoden-Funktionen das globale Objekt (window in Browsern; siehe Das globale Objekt):
functionsloppyFunc(){console.log(this===window);// true}
Im Strikten Modus ist es undefined.
functionstrictFunc(){'use strict';console.log(this===undefined);// true}
Dies ist nützlich für Konstruktoren. Zum Beispiel ist der folgende Konstruktor, Point, im Strikten Modus:
functionPoint(x,y){'use strict';this.x=x;this.y=y;}
Aufgrund des Strikten Modus erhalten Sie eine Warnung, wenn Sie versehentlich new vergessen und ihn als Funktion aufrufen.
> var pt = Point(3, 1); TypeError: Cannot set property 'x' of undefined
Im Locker Modus erhalten Sie keine Warnung, und die globalen Variablen x und y werden erstellt. Konsultieren Sie Tipps zur Implementierung von Konstruktoren für Details.
Illegale Manipulationen von Eigenschaften werfen im Strikten Modus Ausnahmen. Zum Beispiel wirft der Versuch, den Wert einer schreibgeschützten Eigenschaft zu setzen, eine Ausnahme, ebenso wie der Versuch, eine nicht konfigurierbare Eigenschaft zu löschen. Hier ist ein Beispiel für ersteres:
varstr='abc';functionsloppyFunc(){str.length=7;// no effect, silent failureconsole.log(str.length);// 3}functionstrictFunc(){'use strict';str.length=7;// TypeError: Cannot assign to// read-only property 'length'}
Im Locker Modus können Sie eine globale Variable foo wie folgt löschen:
deletefoo
Im Strikten Modus erhalten Sie einen Syntaxfehler, wann immer Sie versuchen, nicht qualifizierte Bezeichner zu löschen. Sie können globale Variablen immer noch wie folgt löschen:
deletewindow.foo;// browsersdeleteglobal.foo;// Node.jsdeletethis.foo;// everywhere (in global scope)
Im Strikten Modus ist die eval()-Funktion weniger eigenartig: Variablen, die im ausgewerteten String deklariert wurden, werden nicht mehr dem den eval() umgebenden Gültigkeitsbereich hinzugefügt. Details finden Sie unter Code mit eval() auswerten.
Zwei weitere JavaScript-Funktionen sind im Strikten Modus verboten.
with-Anweisung ist nicht mehr erlaubt (siehe Die with-Anweisung). Sie erhalten beim Kompilieren (beim Laden des Codes) einen Syntaxfehler.Keine Oktalzahlen mehr: Im Locker Modus wird eine Ganzzahl mit einer führenden Null als Oktalzahl (Basis 8) interpretiert. Zum Beispiel:
> 010 === 8 true
Im Strikten Modus erhalten Sie einen Syntaxfehler, wenn Sie diese Art von Literal verwenden:
> function f() { 'use strict'; return 010 }
SyntaxError: Octal literals are not allowed in strict mode.