4.1 Schnellstart mit der JavaScript-Sprache

Schriftsteller:Gutes, Erstellt: 2019-04-26 11:46:12, aktualisiert: 2019-04-27 11:53:43

Hintergrund

Dieser Abschnitt gibt einen kurzen Überblick über JavaScript, um Ihnen zu helfen zu verstehen, warum es so ist.

JavaScript gegen ECMAScript

ECMAScript ist der offizielle Name für JavaScript. Ein neuer Name wurde notwendig, weil es eine Marke für JavaScript gibt (ursprünglich von Sun, jetzt von Oracle gehalten). Momentan ist Mozilla eines der wenigen Unternehmen, die den Namen JavaScript offiziell verwenden dürfen, weil sie vor langer Zeit eine Lizenz erhalten hat. Für die allgemeine Verwendung gelten folgende Regeln:

  • JavaScript bedeutet die Programmiersprache.
  • ECMAScript ist der Name, der von der Sprachspezifikation verwendet wird. Daher sagen die Leute immer, wenn sie sich auf Versionen der Sprache beziehen. Die aktuelle Version von JavaScript ist ECMAScript 5; ECMAScript 6 wird derzeit entwickelt.

Einflüsse und Art der Sprache

Der Schöpfer von JavaScript, Brendan Eich, hatte keine andere Wahl, als die Sprache sehr schnell zu erstellen (oder andere, schlechtere Technologien wären von Netscape übernommen worden). Er lieh sich mehrere Programmiersprachen: Java (Syntax, primitive Werte gegen Objekte), Scheme und AWK (Erstklasse-Funktionen), Self (prototypische Vererbung) und Perl und Python (Strings, Arrays und reguläre Ausdrücke).

JavaScript hatte bis ECMAScript 3 keine Ausnahmebehandlung, was erklärt, warum die Sprache so oft automatisch Werte konvertiert und so oft stillschweigend versagt: Sie konnte zunächst keine Ausnahmen werfen.

Auf der einen Seite hat JavaScript Eigenschaften und fehlt einiges an Funktionalität (Block-Scope-Variablen, Module, Unterstützung für Unterklassen usw.). Auf der anderen Seite hat es mehrere leistungsstarke Funktionen, mit denen Sie diese Probleme umgehen können. In anderen Sprachen lernen Sie Sprachfunktionen. In JavaScript lernen Sie stattdessen oft Muster.

Angesichts seiner Einflüsse ist es nicht verwunderlich, dass JavaScript einen Programmierstil ermöglicht, der eine Mischung aus funktionaler Programmierung (Funktionen höherer Ordnung; integrierte Karte, reduzieren usw.) und objektorientierter Programmierung (Objekte, Vererbung) ist.

Syntax

Dieser Abschnitt erklärt grundlegende syntaktische Prinzipien von JavaScript.

Ein Überblick über die Syntax

Ein paar Beispiele für die Syntax:

// Two slashes start single-line comments

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 zwei verschiedenen Verwendungen des Gleichheitszeichens:

  • Ein einziges Gleichheitszeichen (=) wird verwendet, um einer Variablen einen Wert zuzuweisen.
  • Ein dreifach gleiches Zeichen (===) wird verwendet, um zwei Werte zu vergleichen (siehe Gleichheitsoperatoren).

Ausdrücke gegen Äußerungen

Um die Syntax von JavaScript zu verstehen, sollten Sie wissen, dass es zwei Hauptsyntaxkategorien hat: Statements und Expressions:

  • Ein Programm ist eine Folge von Anweisungen. Hier ist ein Beispiel für eine Anweisung, die eine Variable foo deklariert (erstellt):
var foo;
  • Ausdrücke erzeugen Werte. Sie sind Funktionsargumente, die rechte Seite einer Zuordnung usw. Hier ist ein Beispiel für einen Ausdruck:
3 * 7

Die Unterscheidung zwischen Statements und Expressions wird am besten durch die Tatsache veranschaulicht, dass JavaScript zwei verschiedene Möglichkeiten hat, if-then-else entweder als Statement auszuführen:

var x;
if (y >= 0) {
    x = y;
} else {
    x = -y;
}

oder als Ausdruck:

var x = y >= 0 ? y : -y;

Sie können letzteres als Funktionsargument verwenden (aber nicht das erstere):

myFunction(y >= 0 ? y : -y)

Schließlich können Sie überall dort, wo JavaScript eine Anweisung erwartet, auch einen Ausdruck verwenden; zum Beispiel:

foo(7, 1);

Die gesamte Zeile ist eine Anweisung (eine sogenannte Ausdrucksanweisung), aber der Funktionsruf foo(7, 1) ist ein Ausdruck.

Mit Semikolon

Semikolon ist in JavaScript optional. Allerdings empfehle ich, sie immer einzubeziehen, da JavaScript sonst das Ende einer Anweisung falsch erraten kann. Die Details werden in Automatic Semicolon Insertion erklärt.

Semikolon beendet Aussagen, aber nicht Blöcke. Es gibt einen Fall, in dem Sie ein Semikolon nach einem Block sehen: ein Funktionsausdruck ist ein Ausdruck, der mit einem Block endet. Wenn ein solcher Ausdruck zuletzt in einer Aussage erscheint, wird er von einem Semikolon gefolgt:

// Pattern: var _ = ___;
var x = 3 * 7;
var f = function () { };  // function expr. inside var decl.

Anmerkungen

JavaScript hat zwei Arten von Kommentaren: Einzeilenkommentare und mehrzeilige Kommentare. Einzeilenkommentare beginnen mit // und werden am Ende der Zeile beendet:

x++; // single-line comment

Kommentare mit mehreren Zeilen werden durch /* und */ begrenzt:

/* This is
   a multiline
   comment.
 */

Variablen und Zuordnung

Variablen in JavaScript werden erklärt, bevor sie verwendet werden:

var foo;  // declare variable `foo`

Zuweisung

Sie können eine Variable deklarieren und gleichzeitig einen Wert zuweisen:

var foo = 6;

Sie können auch einen Wert einer vorhandenen Variablen zuweisen:

foo = 4;  // change variable `foo`

Zusammengesetzte Zuweisungsbetreiber

Es gibt zusammengesetzte Zuweisungsoperatoren wie +=. Die folgenden beiden Zuweisungen sind gleichwertig:

x += 1;
x = x + 1;

Identifikatoren und Variablennamen

Identifikatoren sind Namen, die in JavaScript verschiedene syntaktische Rollen spielen.

Grob gesagt kann das erste Zeichen eines Identifikators jeder beliebige Unicode-Buchstabe, ein Dollarzeichen ($) oder ein Unterzeichen (_) sein.

arg0
_tmp
$elem
π

Die folgenden Identifikatoren sind reservierte Wörter, sie sind Teil der Syntax und können nicht als Variablennamen (einschließlich Funktionsnamen und Parameternamen) verwendet werden:

img

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

img

Schließlich sollten Sie sich auch von den Namen von Standard-globalen Variablen fernhalten. Sie können sie für lokale Variablen verwenden, ohne etwas zu brechen, aber Ihr Code wird immer noch verwirrend.

Werte

JavaScript hat viele Werte, die wir von Programmiersprachen erwarten: Booleaner, Zahlen, Zeichenfolgen, Arrays und so weiter. Alle Werte in JavaScript haben Eigenschaften. Jede Eigenschaft hat einen Schlüssel (oder einen Namen) und einen Wert. Sie können sich Eigenschaften wie Felder eines Datensatzes vorstellen.

value.propKey

Zum Beispiel hat die Zeichenfolge abc die Eigenschaft Länge:

> var str = 'abc';
> str.length
3

Das Vorabwort kann auch so geschrieben werden:

> 'abc'.length
3
The dot operator is also used to assign a value to a property:

> var obj = {};  // empty object
> obj.foo = 123; // create property `foo`, set it to 123
123
> obj.foo
123

Und man kann damit Methoden aufrufen:

> 'hello'.toUpperCase()
'HELLO'

In dem vorherigen Beispiel haben wir die Methode toUpperCase() auf den Wert hello aufgerufen.

Primitive Werte gegen Gegenstände

JavaScript macht eine etwas willkürliche Unterscheidung zwischen den Werten:

  • Die primitiven Werte sind Booleaner, Zahlen, Strings, Null und undefined.
  • Alle anderen Werte sind Objekte. Ein großer Unterschied zwischen den beiden ist, wie sie verglichen werden; Jedes Objekt hat eine einzigartige Identität und ist nur (streng gleich) sich selbst:
> var obj1 = {};  // an empty object
> var obj2 = {};  // another empty object
> obj1 === obj2
false
> obj1 === obj1
true

Im Gegensatz dazu gelten alle primitiven Werte, die denselben Wert codieren, als gleich:

> var prim1 = 123;
> var prim2 = 123;
> prim1 === prim2
true

In den nächsten beiden Abschnitten werden primitive Werte und Objekte detaillierter erläutert.

Ursprüngliche Werte

Die folgenden sind alle primitiven Werte (oder kurz primitives):

  • Booleaner: wahr, falsch (siehe Booleaner)
  • Zahlen: 1736, 1.351 (siehe Zahlen)
  • Strings: abc, abc (siehe Strings)
  • Zwei nicht-Werte: undefiniert, null (siehe undefiniert und null)

Primitive haben folgende Eigenschaften:

Verglichen nach Wert

Der Inhalt wird verglichen:

> 3 === 3
true
> 'abc' === 'abc'
true

Immer unveränderlich Eigenschaften können nicht geändert, hinzugefügt oder entfernt werden:

> var str = 'abc';

> str.length = 1; // try to change property `length`
> str.length      // ⇒ no effect
3

> str.foo = 3; // try to create property `foo`
> str.foo      // ⇒ no effect, unknown property
undefined

(Das Lesen einer unbekannten Eigenschaft gibt immer undefiniert zurück.)

Gegenstände

Alle nicht-primitiven Werte sind Objekte. Die häufigsten Objekttypen sind:

  • Einfache Objekte, die durch Objektliterale erstellt werden können (siehe Einzelobjekte):
{
    firstName: 'Jane',
    lastName: 'Doe'
}

Das vorhergehende Objekt hat zwei Eigenschaften: der Wert der Eigenschaft firstName ist Jane und der Wert der Eigenschaft lastName ist Doe.

  • Arrays, die durch Array-Literals erstellt werden können (siehe Arrays):
[ 'apple', 'banana', 'cherry' ]

Das vorhergehende Array hat drei Elemente, die über numerische Indizes abgerufen werden können.

  • Regelmäßige Ausdrücke, die durch Regelmäßige Ausdrucksliterale erstellt werden können (siehe Regelmäßige Ausdrücke):
/^a+b+$/

Die Objekte weisen folgende Merkmale auf:

Vergleicht nach Referenz

Identitäten werden verglichen; jeder Wert hat seine eigene Identität:

> ({} === {})  // two different empty objects
false

> var obj1 = {};
> var obj2 = obj1;
> obj1 === obj2
true

Voreingestellt mutabel

Normalerweise können Sie Eigenschaften frei ändern, hinzufügen und entfernen (siehe Einzelobjekte):

> var obj = {};
> obj.foo = 123; // add property `foo`
> obj.foo
123

nicht definiert und null

Die meisten Programmiersprachen haben Werte, die fehlende Informationen kennzeichnen.

  • undefined bedeutet keinen Wert. Nicht initialisierte Variablen sind undefiniert:
> var foo;
> foo
undefined

Die fehlenden Parameter sind nicht definiert:

> function f(x) { return x }
> f()
undefined

Wenn man eine nicht existierende Eigenschaft liest, wird man undefiniert:

> var obj = {}; // empty object
> obj.foo
undefined
  • null bedeutet kein Objekt. Es wird als Nichtwert verwendet, wenn ein Objekt erwartet wird (Parameter, letzter in einer Kette von Objekten usw.).

Warnung

undefined und null haben keine Eigenschaften, nicht einmal Standardmethoden wie toString().

Überprüfung auf undefined oder null

Funktionen erlauben es Ihnen normalerweise, einen fehlenden Wert entweder über undefined oder null anzugeben.

if (x === undefined || x === null) {
    ...
}

Sie können auch die Tatsache ausnutzen, dass sowohl undefiniert als auch null als falsch betrachtet werden:

if (!x) {
    ...
}

Warnung

false, 0, NaN und gelten ebenfalls als falsch (siehe Wahr und Falsch).

Kategorisierung von Werten unter Verwendung von Typ und Instanz

Es gibt zwei Operatoren zur Kategorisierung von Werten: typeof wird hauptsächlich für primitive Werte verwendet, während instanceof für Objekte verwendet wird. Der Typ sieht so aus:

typeof value

Er gibt eine Zeichenfolge zurück, die den type des Wertes beschreibt.

> typeof true
'boolean'
> typeof 'abc'
'string'
> typeof {} // empty object literal
'object'
> typeof [] // empty array literal
'object'

In der folgenden Tabelle sind alle Ergebnisse des Typs:

img

typeof null Returning object ist ein Fehler, der nicht behoben werden kann, weil er bestehenden Code brechen würde.

Ein Beispiel sieht so aus:

value instanceof Constr

Es gibt True zurück, wenn der Wert ein Objekt ist, das vom Konstruktor Constr erstellt wurde (siehe Konstruktoren: Fabriken für Objekte).

> var b = new Bar();  // object created by constructor Bar
> b instanceof Bar
true

> {} instanceof Object
true
> [] instanceof Array
true
> [] instanceof Object  // Array is a subconstructor of Object
true

> undefined instanceof Object
false
> null instanceof Object
false

Booleaner

Der primitive Boolean-Typ umfasst die Werte true und false.

  • Binäre logische Operatoren: && (And),
  • Logischer Operator mit Präfix:! (Nicht)
  • Vergleichsoperatoren:Gleichheitsoperatoren: ===,!==, ==,!=
  • Ordnungsoperatoren (für Zeichenfolgen und Zahlen): >, >=, <, <=

Wahres und Falsches

Wenn JavaScript einen Boolean-Wert erwartet (z. B. für die Bedingung einer if-Anweisung), kann jeder Wert verwendet werden. Er wird entweder als wahr oder falsch interpretiert. Die folgenden Werte werden als falsch interpretiert:

  • nicht definiert, null
  • Boolean: falsch
  • Zahl: 0, NaN
  • String:

Alle anderen Werte (einschließlich aller Objekte!) gelten als wahr. Werte, die als falsch interpretiert werden, werden als falsch und Werte, die als wahr interpretiert werden, als wahr bezeichnet.

> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true
> Boolean({}) // empty object
true
> Boolean([]) // empty array
true

Binäre logische Operatoren

Binäre logische Operatoren in JavaScript sind Kurzschluss. Das heißt, wenn der erste Operand ausreicht, um das Ergebnis zu bestimmen, wird der zweite Operand nicht ausgewertet. Zum Beispiel wird in den folgenden Ausdrücken die Funktion foo() nie aufgerufen:

false && foo()
true  || foo()

Darüber hinaus geben binäre logische Operatoren entweder einen ihrer Operanden zurück, der ein Boolean sein kann oder nicht.

Und (&&)

Wenn der erste Operand falsch ist, geben Sie ihn zurück. Ansonsten geben Sie den zweiten Operand zurück:

> NaN && 'abc'
NaN
> 123 && 'abc'
'abc'

Oder (für)

Wenn der erste Operand wahr ist, geben Sie ihn zurück. Ansonsten geben Sie den zweiten Operand zurück:

> 'abc' || 123
'abc'
> '' || 123
123

Gleichstellungsbetreiber

JavaScript hat zwei Arten von Gleichheit:

  • Normal, oder nachsichtig, (in) Gleichheit: == und!=
  • Strikt (in) Gleichheit: === und!==

Normalgleichheit betrachtet (zu) viele Werte als gleich (die Details werden in Normal (Lenient) Equality (==,!=) erläutert), was Fehler verbergen kann. Daher wird immer strenge Gleichheit empfohlen.

Zahlen

Alle Zahlen in JavaScript sind mit einem schwimmenden Komma:

> 1 === 1.0
true

Zu den Sondernummern gehören:

NaN (keine Zahl) Fehlerwert:

> Number('xyz')  // 'xyz' can’t be converted to a number
NaN

Unendlich Auch meistens ein Fehlerwert:

> 3 / 0
Infinity
> Math.pow(2, 1024)  // number too large
Infinity

Unendlichkeit ist größer als jede andere Zahl (außer NaN). Ähnlich ist -Unendlichkeit kleiner als jede andere Zahl (außer NaN). Das macht diese Zahlen als Standardwerte nützlich (z. B. wenn Sie nach einem Minimum oder Maximum suchen).

Betreiber

JavaScript hat folgende arithmetische Operatoren (siehe Arithmetische Operatoren):

  • Zusatz: Nummer 1 + Nummer 2
  • Abziehung: Nummer 1 - Nummer 2
  • Multiplikation: Zahl1 * Zahl2
  • Abteilung: Nr. 1 / Nr. 2
  • Rest: Zahl1 % Zahl2
  • Steigerung: ++variabel, variabel++
  • Decrement: variabel, variabel
  • Negativ: -Wert
  • Umwandlung in Zahl: +wert

Das globale Objekt Mathematik (siehe Mathematik) bietet mehr arithmetische Operationen über Funktionen.

JavaScript hat auch Operatoren für bitwise Operationen (z. B. bitwise And; siehe Bitwise Operatoren).

Strings

Strings können direkt über String-Literals erstellt werden. Diese Literals werden durch einzelne oder doppelte Anführungszeichen begrenzt. Der Backslash () entkommt Zeichen und erzeugt einige Kontrollzeichen. Hier sind einige Beispiele:

'abc'
"abc"

'Did she say "Hello"?'
"Did she say \"Hello\"?"

'That\'s nice!'
"That's nice!"

'Line 1\nLine 2'  // newline
'Backlash: \\'

Einzelzeichen werden über eckige Klammern zugegriffen:

> var str = 'abc';
> str[1]
'b'

Die Eigenschaft length zählt die Anzahl der Zeichen in der Zeichenfolge:

> 'abc'.length
3

Wie alle Primitiven sind Zeichenfolgen unveränderlich; Sie müssen eine neue Zeichenfolge erstellen, wenn Sie eine bestehende ändern möchten.

Stringoperatoren

Strings werden über den Plus (+) -Operator verknüpft, der den anderen Operand in eine Zeichenfolge umwandelt, wenn einer der Operanden eine Zeichenfolge ist:

> var messageCount = 3;
> 'You have ' + messageCount + ' messages'
'You have 3 messages'

Um Zeichenfolgen in mehreren Schritten zu verknüpfen, verwenden Sie den +=-Operator:

> var str = '';
> str += 'Multiple ';
> str += 'pieces ';
> str += 'are concatenated.';
> str
'Multiple pieces are concatenated.'

String-Methoden

Strings haben viele nützliche Methoden (siehe String Prototyp Methoden).

> 'abc'.slice(1)  // copy a substring
'bc'
> 'abc'.slice(1, 2)
'b'

> '\t xyz  '.trim()  // trim whitespace
'xyz'

> 'mjölnir'.toUpperCase()
'MJÖLNIR'

> 'abc'.indexOf('b')  // find a string
1
> 'abc'.indexOf('x')
-1

Erklärungen

In den folgenden Abschnitten werden Bedingungen und Schleifen in JavaScript eingeführt.

Bedingungen

Die if-Anweisung hat eine then-Klausel und eine optionale else-Klausel, die abhängig von einer booleanischen Bedingung ausgeführt werden:

if (myvar === 0) {
    // then
}

if (myvar === 0) {
    // then
} else {
    // else
}

if (myvar === 0) {
    // then
} else if (myvar === 1) {
    // else-if
} else if (myvar === 2) {
    // else-if
} else {
    // else
}

Ich empfehle, immer Klammern zu verwenden (sie kennzeichnen Blöcke mit null oder mehr Anweisungen).

if (x < 0) return -x;

Der Wert von Frucht entscheidet, welcher Fall ausgeführt wird:

switch (fruit) {
    case 'banana':
        // ...
        break;
    case 'apple':
        // ...
        break;
    default:  // all other cases
        // ...
}

Der operand nach dem Fall kann jeder Ausdruck sein; er wird über === mit dem Parameter switch verglichen.

Schleifen

Die For-Schleife hat folgendes Format:

for (⟦«init»⟧; ⟦«condition»⟧; ⟦«post_iteration»⟧)
    «statement»

init wird zu Beginn der Schleife ausgeführt. condition wird vor jeder Schleifeiteration geprüft; wenn es falsch wird, wird die Schleife beendet. post_iteration wird nach jeder Schleifeiteration ausgeführt.

Dieses Beispiel druckt alle Elemente des Arrays arr auf der Konsole:

for (var i=0; i < arr.length; i++) {
    console.log(arr[i]);
}

Die while-Schleife schleift sich über ihren Körper, solange ihr Zustand besteht:

// Same as for loop above:
var i = 0;
while (i < arr.length) {
    console.log(arr[i]);
    i++;
}

Da die Bedingung dem Körper folgt, wird der Körper immer mindestens einmal ausgeführt:

do {
    // ...
} while (condition);

In allen Schleifen:

  • Brechen lässt die Schleife.
  • Weiterfahren beginnt eine neue Schleifeiteration.

Funktionen

Eine Möglichkeit, eine Funktion zu definieren, ist eine Funktionsdeklaration:

function add(param1, param2) {
    return param1 + param2;
}

Der vorhergehende Code definiert eine Funktion, add, die zwei Parameter, param1 und param2, hat und gibt die Summe beider Parameter zurück.

> add(6, 1)
7
> add('a', 'b')
'ab'

Eine andere Möglichkeit, add ((() zu definieren, ist, einer Variablen add einen Funktionsausdruck zuzuweisen:

var add = function (param1, param2) {
    return param1 + param2;
};

Ein Funktionsausdruck erzeugt einen Wert und kann somit verwendet werden, um Funktionen direkt als Argumente an andere Funktionen zu übergeben:

someOtherFunction(function (p1, p2) { ... });

Funktionserklärungen werden gehisst

Funktionsdeklarationen werden vollständig an den Anfang des aktuellen Bereichs gehisst.

function foo() {
    bar();  // OK, bar is hoisted
    function bar() {
        ...
    }
}

Es ist zu beachten, dass, obwohl auch die Variablen-Deklarationen angehoben werden (siehe Variablen werden angehoben), die von ihnen ausgeführten Aufgaben nicht:

function foo() {
    bar();  // Not OK, bar is still undefined
    var bar = function () {
        // ...
    };
}

Die Argumente der Sondervariablen

Sie können jede Funktion in JavaScript mit einer beliebigen Anzahl von Argumenten aufrufen; die Sprache wird sich nie beschweren. Sie wird jedoch alle Parameter über die speziellen Variablenargumente verfügbar machen. argumente sieht aus wie ein Array, hat aber keine der Array-Methoden:

> function f() { return arguments }
> var args = f('a', 'b', 'c');
> args.length
3
> args[0]  // read element at index 0
'a'

Zu viele oder zu wenige Streitigkeiten

Lassen Sie uns die folgende Funktion verwenden, um zu erforschen, wie zu viele oder zu wenige Parameter in JavaScript behandelt werden (die Funktion toArray( wird in Konvertieren von Argumenten in ein Array gezeigt):

function f(x, y) {
    console.log(x, y);
    return toArray(arguments);
}

Zusätzliche Parameter werden ignoriert (außer durch Argumente):

> f('a', 'b', 'c')
a b
[ 'a', 'b', 'c' ]

Fehlende Parameter werden den Wert undefiniert:

> f('a')
a undefined
[ 'a' ]
> f()
undefined undefined
[]

Optionale Parameter

Folgendes ist ein übliches Muster für die Zuweisung von Standardwerten an Parameter:

function pair(x, y) {
    x = x || 0;  // (1)
    y = y || 0;
    return [ x, y ];
}

In Zeile (1) gibt der Operator x zurück, wenn er wahr ist (nicht null, undefined usw.). Ansonsten gibt er den zweiten Operand zurück:

> pair()
[ 0, 0 ]
> pair(3)
[ 3, 0 ]
> pair(3, 5)
[ 3, 5 ]

Eine Arität erzwingen

Wenn Sie eine Arity (eine bestimmte Anzahl von Parametern) durchsetzen möchten, können Sie arguments.length überprüfen:

function pair(x, y) {
    if (arguments.length !== 2) {
        throw new Error('Need exactly 2 arguments');
    }
    ...
}

Umwandlung von Argumenten in ein Array

arguments ist kein Array, es ist nur arrayähnlich (siehe Array-like Objects and Generic Methods). Es hat eine Eigenschaftslänge und Sie können auf seine Elemente über Indizes in Quadratklammern zugreifen. Sie können jedoch keine Elemente entfernen oder eine der Array-Methoden darauf aufrufen. Daher müssen Sie manchmal Argumente in ein Array konvertieren, was die folgende Funktion tut (es wird in Array-like Objects und Generic Methods erklärt):

function toArray(arrayLikeObject) {
    return Array.prototype.slice.call(arrayLikeObject);
}

Ausnahmebehandlung

Die häufigste Art, mit Ausnahmen umzugehen (siehe Kapitel 14), ist wie folgt:

function getPerson(id) {
    if (id < 0) {
        throw new Error('ID must not be negative: '+id);
    }
    return { id: id }; // normally: retrieved from database
}

function getPersons(ids) {
    var result = [];
    ids.forEach(function (id) {
        try {
            var person = getPerson(id);
            result.push(person);
        } catch (exception) {
            console.log(exception);
        }
    });
    return result;
}

Die Try-Klausel umringt kritischen Code, und die Catch-Klausel wird ausgeführt, wenn eine Ausnahme in die Try-Klausel geworfen wird.

> getPersons([2, -5, 137])
[Error: ID must not be negative: -5]
[ { id: 2 }, { id: 137 } ]

Strenger Modus

Der strenge Modus (siehe Strenge Modus) ermöglicht mehr Warnungen und macht JavaScript zu einer saubereren Sprache (nicht strenger Modus wird manchmal sloppy-Modus genannt).

'use strict';

Sie können auch den strengen Modus pro Funktion aktivieren:

function functionInStrictMode() {
    'use strict';
}

Variabler Anwendungsbereich und Schließungen

In JavaScript deklarieren Sie Variablen über var, bevor Sie sie verwenden:

> var x;
> x
undefined
> y
ReferenceError: y is not defined

Sie können mehrere Variablen mit einer einzigen Var-Anweisung deklarieren und initialisieren:

var x = 1, y = 2, z = 3;

Aber ich empfehle, eine Anweisung pro Variable zu verwenden (der Grund wird in Syntax erklärt).

var x = 1;
var y = 2;
var z = 3;

Wegen des Hebens (siehe Variablen werden gehisst) ist es normalerweise am besten, Variablen zu Beginn einer Funktion zu deklarieren.

Variablen sind funktionsgebunden

Der Umfang einer Variablen ist immer die vollständige Funktion (im Gegensatz zum aktuellen Block).

function foo() {
    var x = -512;
    if (x < 0) {  // (1)
        var tmp = -x;
        ...
    }
    console.log(tmp);  // 512
}

Wir können sehen, dass die Variable tmp nicht auf den Block beschränkt ist, der in Zeile (1) beginnt; sie existiert bis zum Ende der Funktion.

Variablen werden angehoben

Jede Variabeldeklaration wird angehoben: Die Erklärung wird an den Anfang der Funktion verschoben, aber die damit verbundenen Aufgaben bleiben gesetzt.

function foo() {
    console.log(tmp); // undefined
    if (false) {
        var tmp = 3;  // (1)
    }
}

Intern wird die vorhergehende Funktion wie folgt ausgeführt:

function foo() {
    var tmp;  // hoisted declaration
    console.log(tmp);
    if (false) {
        tmp = 3;  // assignment stays put
    }
}

Schließungen

Jede Funktion bleibt mit den Variablen der Funktionen, die sie umgeben, verbunden, auch nachdem sie den Umfang verlassen hat, in dem sie erstellt wurde.

function createIncrementor(start) {
    return function () {  // (1)
        start++;
        return start;
    }
}

Die Funktion, die in Zeile (1) beginnt, verlässt den Kontext, in dem sie erstellt wurde, bleibt aber mit einer Live-Version von start verbunden:

> var inc = createIncrementor(5);
> inc()
6
> inc()
7
> inc()
8

Eine Schließung ist eine Funktion plus die Verbindung zu den Variablen ihrer umgebenden Bereiche.

Das IIFE-Muster: Einführung eines neuen Anwendungsbereichs

Manchmal möchten Sie einen neuen Variablenbereich einführen, um beispielsweise zu verhindern, dass eine Variable global wird. In JavaScript können Sie dafür keinen Block verwenden; Sie müssen eine Funktion verwenden. Aber es gibt ein Muster für die Verwendung einer Funktion in einer blockartigen Weise. Es heißt IIFE (immediately invoked function expression, ausgesprochen iffy):

(function () {  // open IIFE
    var tmp = ...;  // not a global variable
}());  // close IIFE

Bitte geben Sie das vorherige Beispiel genau wie gezeigt ein (abgesehen von den Kommentaren). Ein IIFE ist ein Funktionsausdruck, der unmittelbar nach der Definition aufgerufen wird. Innerhalb der Funktion existiert ein neuer Bereich, der verhindert, dass tmp global wird.

IIFE-Anwendungsfall: unbeabsichtigte gemeinsame Nutzung durch Schließungen

Schließungen halten ihre Verbindungen zu äußeren Variablen, was manchmal nicht das ist, was Sie wollen:

var result = [];
for (var i=0; i < 5; i++) {
    result.push(function () { return i });  // (1)
}
console.log(result[1]()); // 5 (not 1)
console.log(result[3]()); // 5 (not 3)

Der Wert, der in Zeile (1) zurückgegeben wird, ist immer der aktuelle Wert von i, nicht der Wert, den er hatte, als die Funktion erstellt wurde. Nachdem die Schleife beendet ist, hat i den Wert 5, weshalb alle Funktionen im Array diesen Wert zurückgeben. Wenn Sie möchten, dass die Funktion in Zeile (1) einen Schnappschuss des aktuellen Wertes von i erhält, können Sie einen IIFE verwenden:

for (var i=0; i < 5; i++) {
    (function () {
        var i2 = i; // copy current i
        result.push(function () { return i2 });
    }());
}

Objekte und Konstrukteure

Dieser Abschnitt behandelt zwei grundlegende objektorientierte Mechanismen von JavaScript: Einzelobjekte und Konstruktoren (die Fabriken für Objekte sind, ähnlich wie Klassen in anderen Sprachen).

Einzelne Ziele

Wie alle Werte haben auch Objekte Eigenschaften. Man könnte tatsächlich ein Objekt als eine Reihe von Eigenschaften betrachten, wobei jede Eigenschaft ein (Schlüssel, Wert) Paar ist. Der Schlüssel ist eine Zeichenfolge und der Wert ist ein beliebiger JavaScript-Wert.

In JavaScript können Sie einfache Objekte direkt über Objektliteralen erstellen:

'use strict';
var jane = {
    name: 'Jane',

    describe: function () {
        return 'Person named '+this.name;
    }
};

Das vorhergehende Objekt hat die Eigenschaften name und describe.

> jane.name  // get
'Jane'
> jane.name = 'John';  // set
> jane.newProperty = 'abc';  // property created automatically

Funktionswerte Eigenschaften wie describe werden Methoden genannt. Sie verwenden dies, um sich auf das Objekt zu beziehen, das verwendet wurde, um sie zu rufen:

> jane.describe()  // call method
'Person named John'
> jane.name = 'Jane';
> jane.describe()
'Person named Jane'

Der in-Operator prüft, ob eine Eigenschaft existiert:

> 'newProperty' in jane
true
> 'foo' in jane
false

Wenn Sie eine Eigenschaft lesen, die nicht existiert, erhalten Sie den Wert undefined. Daher könnten die beiden vorherigen Prüfungen auch so durchgeführt werden:

> jane.newProperty !== undefined
true
> jane.foo !== undefined
false

Der Delete Operator entfernt eine Eigenschaft:

> delete jane.newProperty
true
> 'newProperty' in jane
false

Willkürliche Eigentumsschlüssel

Ein Eigenschaftsschlüssel kann eine beliebige Zeichenfolge sein. Bisher haben wir Eigenschaftsschlüssel in Objektliteralen und nach dem Punktoperator gesehen. Sie können sie jedoch nur so verwenden, wenn sie Identifikatoren sind (siehe Identifikatoren und Variablennamen). Wenn Sie andere Zeichenfolgen als Schlüssel verwenden möchten, müssen Sie sie in einem Objektliteralen zitieren und quadratische Klammern verwenden, um die Eigenschaft zu erhalten und festzulegen:

> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123
> obj['not an identifier'] = 456;

Quadratische Klammern erlauben es Ihnen auch, den Schlüssel einer Eigenschaft zu berechnen:

> var obj = { hello: 'world' };
> var x = 'hello';

> obj[x]
'world'
> obj['hel'+'lo']
'world'

Extraktionsmethoden

Wenn Sie eine Methode extrahieren, verliert sie ihre Verbindung mit dem Objekt. Alleine ist die Funktion keine Methode mehr, und dies hat den Wert undefined (im strengen Modus).

Als Beispiel, lassen Sie uns zu dem früheren Objekt Jane zurückgehen:

'use strict';
var jane = {
    name: 'Jane',

    describe: function () {
        return 'Person named '+this.name;
    }
};

Wir wollen die Methode describe aus jane extrahieren, in eine Variable funk einfügen und aufrufen.

> var func = jane.describe;
> func()
TypeError: Cannot read property 'name' of undefined

Die Lösung besteht darin, die Methode bind() zu verwenden, die alle Funktionen haben.

> var func2 = jane.describe.bind(jane);
> func2()
'Person named Jane'

Funktionen innerhalb einer Methode

Jede Funktion hat ihre eigene spezielle Variable this. Dies ist unangenehm, wenn Sie eine Funktion in einer Methode nisten, da Sie nicht von der Funktion aus auf die Methode s this zugreifen können.

var jane = {
    name: 'Jane',
    friends: [ 'Tarzan', 'Cheeta' ],
    logHiToFriends: function () {
        'use strict';
        this.friends.forEach(function (friend) {
            // `this` is undefined here
            console.log(this.name+' says hi to '+friend);
        });
    }
}

Aufrufen von logHiToFriends erzeugt einen Fehler:

> jane.logHiToFriends()
TypeError: Cannot read property 'name' of undefined

Lassen Sie uns zwei Möglichkeiten betrachten, dies zu beheben.

logHiToFriends: function () {
    'use strict';
    var that = this;
    this.friends.forEach(function (friend) {
        console.log(that.name+' says hi to '+friend);
    });
}

Oder, forEach hat einen zweiten Parameter, der es Ihnen erlaubt, einen Wert dafür bereitzustellen:

logHiToFriends: function () {
    'use strict';
    this.friends.forEach(function (friend) {
        console.log(this.name+' says hi to '+friend);
    }, this);
}

Funktionsausdrücke werden häufig als Argumente in Funktionsanrufen in JavaScript verwendet.

Konstrukteure: Fabriken für Gegenstände

Bis jetzt haben Sie vielleicht gedacht, dass JavaScript-Objekte nur Karten von Zeichenfolgen zu Werten sind, eine Vorstellung, die von JavaScripts Objektliteralen vorgeschlagen wird, die wie die Karte/Wörterbuchliteralen anderer Sprachen aussehen. Allerdings unterstützen JavaScript-Objekte auch eine Eigenschaft, die wirklich objektorientiert ist: Vererbung. Dieser Abschnitt erklärt nicht vollständig, wie JavaScript-Vererbung funktioniert, aber er zeigt Ihnen ein einfaches Muster, um loszulegen. Wollen Sie mehr wissen, lesen Sie Kapitel 17.

Neben real Funktionen und Methoden spielen Funktionen eine andere Rolle in JavaScript: Sie werden zu KonstruktorenFabriken für Objekte, wenn sie über den neuen Operator aufgerufen werden. Konstruktoren sind somit ein grobes Analogon zu Klassen in anderen Sprachen.

// Set up instance data
function Point(x, y) {
    this.x = x;
    this.y = y;
}
// Methods
Point.prototype.dist = function () {
    return Math.sqrt(this.x*this.x + this.y*this.y);
};

Wir können sehen, dass ein Konstruktor zwei Teile hat. Erstens setzt die Funktion Point die Instanzdaten ein. Zweitens enthält die Eigenschaft Point.prototype ein Objekt mit den Methoden. Die ersteren Daten sind für jede Instanz spezifisch, während die letzteren Daten unter allen Instanzen geteilt werden.

Um Point zu verwenden, rufen wir ihn über den neuen Operator auf:

> var p = new Point(3, 5);
> p.x
3
> p.dist()
5.830951894845301

p ist eine Instanz von Point:

> p instanceof Point
true

Arrays

Arrays sind Sequenzen von Elementen, auf die man über ganzzahlige Indizes ab Null zugreifen kann.

Array Literals

Array-Literals sind nützlich, um Arrays zu erstellen:

> var arr = [ 'a', 'b', 'c' ];

Das vorhergehende Array besteht aus drei Elementen: den Zeichenfolgen a, b und c. Sie können über ganze Zahlenindizes darauf zugreifen:

> arr[0]
'a'
> arr[0] = 'x';
> arr
[ 'x', 'b', 'c' ]

Die length-Eigenschaft gibt an, wie viele Elemente ein Array hat.

> var arr = ['a', 'b'];
> arr.length
2

> arr[arr.length] = 'c';
> arr
[ 'a', 'b', 'c' ]
> arr.length
3

> arr.length = 1;
> arr
[ 'a' ]

Der in-Operator funktioniert auch für Arrays:

> var arr = [ 'a', 'b', 'c' ];
> 1 in arr // is there an element at index 1?
true
> 5 in arr // is there an element at index 5?
false

Beachten Sie, dass Arrays Objekte sind und somit Objekteigenschaften haben können:

> var arr = [];
> arr.foo = 123;
> arr.foo
123

Array-Methoden

Arrays haben viele Methoden (siehe Array Prototyp Methoden). Hier sind einige Beispiele:

> var arr = [ 'a', 'b', 'c' ];

> arr.slice(1, 2)  // copy elements
[ 'b' ]
> arr.slice(1)
[ 'b', 'c' ]

> arr.push('x')  // append an element
4
> arr
[ 'a', 'b', 'c', 'x' ]

> arr.pop()  // remove last element
'x'
> arr
[ 'a', 'b', 'c' ]

> arr.shift()  // remove first element
'a'
> arr
[ 'b', 'c' ]

> arr.unshift('x')  // prepend an element
3
> arr
[ 'x', 'b', 'c' ]

> arr.indexOf('b')  // find the index of an element
1
> arr.indexOf('y')
-1

> arr.join('-')  // all elements in a single string
'x-b-c'
> arr.join('')
'xbc'
> arr.join()
'x,b,c'

Iteration über Arrays

Es gibt mehrere Array-Methoden für die Iteration über Elemente (siehe Iteration (Nondestructive)). Die beiden wichtigsten sind forEach und map.

forEach iteriert über ein Array und übergibt das aktuelle Element und seinen Index an eine Funktion:

[ 'a', 'b', 'c' ].forEach(
    function (elem, index) {  // (1)
        console.log(index + '. ' + elem);
    });

Der vorhergehende Code erzeugt folgende Ausgabe:

0. a
1. b
2. c

Beachten Sie, dass die Funktion in Zeile (1) frei ist, Argumente zu ignorieren.

map erstellt ein neues Array, indem es jedes Element eines vorhandenen Arrays mit einer Funktion bedient:

> [1,2,3].map(function (x) { return x*x })
[ 1, 4, 9 ]

Regelmäßige Ausdrücke

JavaScript unterstützt regelmäßige Ausdrücke, die mit Schrägstücken begrenzt sind:

/^abc$/
/[A-Za-z0-9]+/

Methoden-Test: Gibt es eine Übereinstimmung?

> /^a+b+$/.test('aaab')
true
> /^a+b+$/.test('aaa')
false

Methode exec ((): Übereinstimmungs- und Erfassungsgruppen

> /a(b+)a/.exec('_abbba_aba_')
[ 'abbba', 'bbb' ]

Das zurückgegebene Array enthält die komplette Übereinstimmung bei Index 0, die Erfassung der ersten Gruppe bei Index 1 und so weiter.

Methode replace ((): Suchen und Ersetzen

> '<a> <bbb>'.replace(/<(.*?)>/g, '[$1]')
'[a] [bbb]'

Der erste Parameter von replace muss ein regulärer Ausdruck mit einem /g-Flag sein; ansonsten wird nur das erste Vorkommen ersetzt.

Mathematik

Mathematik ist ein Objekt mit arithmetischen Funktionen.

> Math.abs(-2)
2

> Math.pow(3, 2)  // 3 to the power of 2
9

> Math.max(2, -1, 5)
5

> Math.round(1.9)
2

> Math.PI  // pre-defined constant for π
3.141592653589793

> Math.cos(Math.PI)  // compute the cosine for 180°
-1

Mehr