Kapitel 7. JavaScripts Syntax
Inhaltsverzeichnis
Das Buch kaufen
(Werbung, bitte nicht blockieren.)

Kapitel 7. JavaScripts Syntax

JavaScripts Syntax ist ziemlich unkompliziert. Dieses Kapitel beschreibt Dinge, auf die Sie achten sollten.

Überblick über die Syntax

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-linecomments

var x;  // declaring a variable

x = 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 statement
if (x === 0) {  // Is `x` equal to zero?
    x = 123;
}

// Defining function `baz` with parameters `a` and `b`
function baz(a, b) {
    return a + b;
}

Beachten Sie die beiden unterschiedlichen Verwendungen von dem Gleichheitszeichen:

Dieser Abschnitt betrachtet eine wichtige syntaktische Unterscheidung in JavaScript: den Unterschied zwischen Ausdrücken und Anweisungen.

Anweisungen

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.

Bedingte Anweisung versus bedingte Ausdrücke

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:

var salutation;
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:

var salutation = (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.

Verwendung von mehrdeutigen Ausdrücken als Anweisungen

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:

    function foo() { }

    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

  • Eine geschweifte Klammer
  • Das Schlüsselwort function

Wenn 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.

Auswerten eines Objektliterals über eval()

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 }

Sofortiges Aufrufen eines Funktionsausdrucks

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 name

Wenn 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.

Kontrollflussanweisungen und Blöcke

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.

Regeln für die Verwendung von Semikolons

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.

Kein Semikolon nach einer Anweisung, die mit einem Block endet

Die folgenden Anweisungen werden nicht durch Semikolons beendet, wenn sie mit einem Block enden:

  • Schleifen: for, while (aber nicht do-while)
  • Verzweigungen: if, switch, try
  • Funktionsdeklarationen (aber nicht Funktionsausdrücke)

Hier ist ein Beispiel für while im Vergleich zu do-while

while (a > 0) {
    a--;
} // no semicolon

do {
    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)

function foo() {
    // ...
} // no semicolon

var foo = function () {
    // ...
};

Hinweis

Wenn Sie nach einem Block ein Semikolon hinzufügen, erhalten Sie keinen Syntaxfehler, da es als leere Anweisung betrachtet wird (siehe nächster Abschnitt).

Tipp

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.

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

  • Ein Zeilenumbruch (z. B. eine neue Zeile) gefolgt von einem ungültigen Token.
  • Eine schließende Klammer angetroffen wird.
  • Das Ende der Datei erreicht ist.

Beispiel: ASI durch ungültiges Token

Der folgende Code enthält einen Zeilenumbruch gefolgt von einem ungültigen Token:

if (a < 0) a = 0
console.log(a)

Das Token console ist nach 0 ungültig und löst ASI aus.

if (a < 0) a = 0;
console.log(a);

Beispiel: ASI durch schließende Klammer

Im folgenden Code wird die Anweisung innerhalb der geschweiften Klammern nicht durch ein Semikolon beendet:

function add(a,b) { return a+b }

ASI erstellt eine syntaktisch korrekte Version des vorherigen Codes.

function add(a,b) { return a+b; }

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:

arguments

break

case

catch

class

const

continue

debugger

default

delete

do

else

enum

export

extends

false

finally

for

Funktion

if

implements

import

in

instanceof

interface

let

new

null

package

private

protected

public

return

Statisch

super

switch

this

throw

true

try

typeof

var

void

while

Die folgenden drei Bezeichner sind keine reservierten Wörter, aber Sie sollten sie so behandeln, als wären sie es.

Infinity

NaN

undefined

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.

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:

function foo() {
    'use strict';
    ...
}

Dies ist praktisch, wenn Sie mit einer Altkodebasis arbeiten, bei der das Einschalten des Strikten Modus überall Dinge kaputt machen kann.

Der Strikte Modus beschränkt funktionsbezogene Merkmale.

this ist in Nicht-Methoden-Funktionen undefiniert.

Im Locker Modus ist der Wert von this in Nicht-Methoden-Funktionen das globale Objekt (window in Browsern; siehe Das globale Objekt):

function sloppyFunc() {
    console.log(this === window);  // true
}

Im Strikten Modus ist es undefined.

function strictFunc() {
    'use strict';
    console.log(this === undefined);  // true
}

Dies ist nützlich für Konstruktoren. Zum Beispiel ist der folgende Konstruktor, Point, im Strikten Modus:

function Point(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.

Im Strikten Modus verbotene Funktionen

Zwei weitere JavaScript-Funktionen sind im Strikten Modus verboten.



[8] Um die Dinge einfach zu halten, tue ich so, als wären Deklarationen Anweisungen.

Weiter: 8. Werte