Kapitel 1. Grundlegendes JavaScript
Inhaltsverzeichnis
Das Buch kaufen
(Werbung, bitte nicht blockieren.)

Kapitel 1. Grundlegendes JavaScript

Dieses Kapitel befasst sich mit „Grundlegendem JavaScript“, einem Namen, den ich für eine möglichst knappe Teilmenge von JavaScript gewählt habe, die Ihnen dennoch produktives Arbeiten ermöglicht. Wenn Sie anfangen, JavaScript zu lernen, empfehle ich Ihnen, eine Weile damit zu programmieren, bevor Sie sich mit dem Rest der Sprache befassen. So müssen Sie nicht alles auf einmal lernen, was verwirrend sein kann.

Hintergrund

Dieser Abschnitt gibt einen kurzen Hintergrund zu JavaScript, um Ihnen zu helfen zu verstehen, warum es so ist, wie es ist.

JavaScript im Vergleich zu ECMAScript

ECMAScript ist der offizielle Name für JavaScript. Ein neuer Name wurde notwendig, da es eine Marke für JavaScript gibt (ursprünglich von Sun, jetzt von Oracle gehalten). Derzeit ist Mozilla eines der wenigen Unternehmen, denen es gestattet ist, den Namen JavaScript offiziell zu verwenden, da es vor langer Zeit eine Lizenz erhalten hat. Für den allgemeinen Sprachgebrauch gelten folgende Regeln:

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

Einflüsse und Natur der Sprache

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

JavaScript hatte bis ECMAScript 3 keine Ausnahmebehandlung. Dies erklärt, warum die Sprache Werte so oft automatisch konvertiert und so oft stillschweigend fehlschlägt: Sie konnte anfangs keine Ausnahmen auslösen.

Einerseits hat JavaScript Eigenheiten und es fehlt ihm einiges an Funktionalität (blockbezogene Variablen, Module, Unterstützung für Unterklassen usw.). Andererseits verfügt es über mehrere leistungsstarke Funktionen, mit denen Sie diese Probleme umgehen können. In anderen Sprachen lernen Sie Sprachfunktionen. In JavaScript lernen Sie oft stattdessen Muster.

Angesichts seiner Einflüsse ist es keine Überraschung, dass JavaScript einen Programmierstil ermöglicht, der eine Mischung aus funktionaler Programmierung (Higher-Order-Funktionen; integrierte map, reduce usw.) und objektorientierter Programmierung (Objekte, Vererbung) ist.

Syntax

Dieser Abschnitt erklärt grundlegende syntaktische Prinzipien von JavaScript.

Anweisungen im Vergleich zu Ausdrücken

Um die Syntax von JavaScript zu verstehen, sollten Sie wissen, dass sie zwei Hauptsynthesekategorien hat: Anweisungen und Ausdrücke:

  • Anweisungen „tun Dinge“. Ein Programm ist eine Sequenz 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 Zuweisung usw. Hier ist ein Beispiel für einen Ausdruck

    3 * 7

Der Unterschied zwischen Anweisungen und Ausdrücken wird am besten dadurch verdeutlicht, dass JavaScript zwei verschiedene Möglichkeiten hat, if-then-else zu tun – entweder als Anweisung:

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

oder als Ausdruck

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

Letzteres können Sie als Funktionsargument verwenden (aber nicht ersteres)

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 Funktionsaufruf foo(7, 1) ist ein Ausdruck.

Semikolons

Semikolons sind in JavaScript optional. Ich empfehle jedoch, sie immer einzufügen, da JavaScript andernfalls falsch über das Ende einer Anweisung raten kann. Die Details werden in Automatischer Semikolon-Einfügung erläutert.

Semikolons beenden Anweisungen, aber keine Blöcke. Es gibt einen Fall, in dem Sie ein Semikolon nach einem Block sehen werden: Ein Funktionsausdruck ist ein Ausdruck, der mit einem Block endet. Wenn ein solcher Ausdruck zuletzt in einer Anweisung kommt, folgt ihm ein Semikolon:

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

Kommentare

JavaScript hat zwei Arten von Kommentaren: einzeilige Kommentare und mehrzeilige Kommentare. Einzeilige Kommentare beginnen mit // und enden am Zeilenende:

x++; // single-line comment

Mehrzeilige Kommentare werden durch /* und */ abgegrenzt:

/* This is
   a multiline
   comment.
 */

Variablen und Zuweisung

Variablen werden in JavaScript deklariert, bevor sie verwendet werden:

var foo;  // declare variable `foo`

Bezeichner und Variablennamen

Bezeichner sind Namen, die in JavaScript verschiedene syntaktische Rollen spielen. Zum Beispiel ist der Name einer Variablen ein Bezeichner. Bezeichner sind Groß- und Kleinschreibungsempfindlich.

Ungefähr kann das erste Zeichen eines Bezeichners ein beliebiges Unicode-Buchstabe, ein Dollarzeichen ($) oder ein Unterstrich (_) sein. Nachfolgende Zeichen können zusätzlich jede Unicode-Ziffer sein. Daher sind die folgenden alle gültige Bezeichner

arg0
_tmp
$elem
π

Die folgenden Bezeichner sind reservierte Wörter – sie sind Teil der Syntax und können nicht als Variablenamen (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.

Werte

JavaScript hat viele Werte, die wir von Programmiersprachen erwarten: Booleans, Zahlen, Zeichenketten, Arrays und so weiter. Alle Werte in JavaScript haben Eigenschaften.[1] Jede Eigenschaft hat einen Schlüssel (oder Namen) und einen Wert. Sie können sich Eigenschaften wie Felder eines Datensatzes vorstellen. Sie verwenden den Punktoperator (.), um eine Eigenschaft zu lesen

value.propKey

Zum Beispiel hat der String 'abc' die Eigenschaft length

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

Das Vorherige kann auch geschrieben werden als

> 'abc'.length
3

Der Punktoperator wird auch verwendet, um einen Wert einer Eigenschaft zuzuweisen:

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

Und Sie können ihn verwenden, um Methoden aufzurufen:

> 'hello'.toUpperCase()
'HELLO'

Im obigen Beispiel haben wir die Methode toUpperCase() für den Wert 'hello' aufgerufen.

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

Primitives haben die folgenden Merkmale:

Vergleich 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 undefined zurück.)

Objekte

Alle nicht-primitiven Werte sind Objekte. Die gängigsten Arten von Objekten sind:

Objekte haben die folgenden Merkmale:

Vergleich 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
Standardmäßig veränderlich

Sie können Eigenschaften normalerweise frei ändern, hinzufügen und entfernen (siehe Einzelne Objekte)

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

Werte kategorisieren mit typeof und instanceof

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.

typeof sieht so aus

typeof value

Es gibt einen String zurück, der den „Typ“ von value beschreibt. Hier sind einige Beispiele

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

Die folgende Tabelle listet alle Ergebnisse von typeof auf

OperandErgebnis

undefined

'undefined'

null

'object'

Boolean-Wert

'boolean'

Zahlenwert

'number'

String-Wert

'string'

Funktion

'function'

Alle anderen normalen Werte

'object'

(Vom Engine erzeugter Wert)

JavaScript-Engines dürfen Werte erzeugen, für die typeof beliebige Zeichenketten zurückgibt (unterschiedlich von allen in dieser Tabelle aufgeführten Ergebnissen).

typeof null gibt 'object' zurück, was ein Fehler ist, der nicht behoben werden kann, da er bestehenden Code brechen würde. Es bedeutet nicht, dass null ein Objekt ist.

instanceof sieht so aus

value instanceof Constr

Es gibt true zurück, wenn value ein Objekt ist, das vom Konstruktor Constr erstellt wurde (siehe Konstruktoren: Fabriken für Objekte). Hier sind einige Beispiele

> 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

Booleans

Der primitive boolesche Typ umfasst die Werte true und false. Die folgenden Operatoren erzeugen Booleans:

  • Binäre logische Operatoren: && (Und), || (Oder)
  • Präfix logischer Operator: ! (Nicht)
  • Vergleichsoperatoren

    • Gleichheitsoperatoren: ===, !==, ==, !=
    • Ordnungsoperatoren (für Zeichenketten und Zahlen): >, >=, <, <=

Truthy und Falsy

Immer wenn JavaScript einen booleschen Wert erwartet (z. B. für die Bedingung einer if-Anweisung), kann jeder Wert verwendet werden. Er wird als true oder false interpretiert. Die folgenden Werte werden als false interpretiert

  • undefined, null
  • Boolean: false
  • Number: 0, NaN
  • String: ''

Alle anderen Werte (einschließlich aller Objekte!) werden als true betrachtet. Werte, die als false interpretiert werden, werden falsy genannt, und Werte, die als true interpretiert werden, werden truthy genannt. Boolean(), als Funktion aufgerufen, konvertiert seinen Parameter in einen Boolean. Sie können es verwenden, um zu testen, wie ein Wert interpretiert wird

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

Zahlen

Alle Zahlen in JavaScript sind Gleitkommazahlen:

> 1 === 1.0
true

Spezielle Zahlen umfassen die folgenden:

NaN („not a number“)

Ein Fehlerwert

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

Auch meist ein Fehlerwert:

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

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

Operatoren

JavaScript hat die folgenden arithmetischen Operatoren (siehe Arithmetische Operatoren)

  • Addition: number1 + number2
  • Subtraktion: number1 - number2
  • Multiplikation: number1 * number2
  • Division: number1 / number2
  • Rest: number1 % number2
  • Inkrement: ++variable, variable++
  • Dekrement: --variable, variable--
  • Negation: -value
  • Konvertierung zu Zahl: +value

Das globale Objekt Math (siehe Math) bietet weitere arithmetische Operationen über Funktionen.

JavaScript hat auch Operatoren für Bit-Operationen (z. B. Bitweises Und; siehe Bitweise Operatoren).

Strings

Zeichenketten können direkt über Zeichenkettenliterale erstellt werden. Diese Literale werden durch einfache oder doppelte Anführungszeichen begrenzt. Der Backslash (\) maskiert Zeichen und erzeugt einige Steuerzeichen. 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: \\'

Einzelne Zeichen werden über eckige Klammern abgerufen:

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

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

> 'abc'.length
3

Wie alle Primitives sind Zeichenketten unveränderlich; Sie müssen eine neue Zeichenkette erstellen, wenn Sie eine vorhandene ändern möchten.

Zeichenketten haben viele nützliche Methoden (siehe String-Prototyp-Methoden). Hier sind einige Beispiele

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

Anweisungen

Bedingungen und Schleifen in JavaScript werden in den folgenden Abschnitten vorgestellt.

Eine Möglichkeit, eine Funktion zu definieren, ist über eine Funktionsdeklaration

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

Der vorherige Code definiert eine Funktion, add, die zwei Parameter hat, param1 und param2, und die Summe beider Parameter zurückgibt. So ruft man diese Funktion auf

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

Eine andere Möglichkeit, add() zu definieren, ist die Zuweisung eines Funktionsausdrucks zu einer Variablen add:

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

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

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

Die spezielle Variable arguments

Sie können jede Funktion in JavaScript mit einer beliebigen Anzahl von Argumenten aufrufen; die Sprache wird nie klagen. Sie wird jedoch alle Parameter über die spezielle Variable arguments verfügbar machen. arguments 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 Argumente

Verwenden wir die folgende Funktion, um zu untersuchen, wie zu viele oder zu wenige Parameter in JavaScript behandelt werden (die Funktion toArray() wird in Argumente in ein Array konvertieren gezeigt)

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

Zusätzliche Parameter werden ignoriert (außer von arguments)

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

Fehlende Parameter erhalten den Wert undefined:

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

Fehlerbehandlung

Der häufigste Weg zur Behandlung von Ausnahmen (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 umschließt kritischen Code, und die catch-Klausel wird ausgeführt, wenn innerhalb der try-Klausel eine Ausnahme ausgelöst wird. Bei Verwendung des vorherigen Codes:

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

In JavaScript deklarieren Sie Variablen mit 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). Daher würde ich die vorherige Anweisung wie folgt umschreiben

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

Aufgrund des Hoisting (siehe Variablen werden gehoben) ist es normalerweise am besten, Variablen am Anfang einer Funktion zu deklarieren.

Manchmal möchten Sie einen neuen Variablen-Geltungsbereich einführen – zum Beispiel, um zu verhindern, dass eine Variable global wird. In JavaScript können Sie keinen Block dafür verwenden; Sie müssen eine Funktion verwenden. Aber es gibt ein Muster, um eine Funktion blockähnlich zu verwenden. Es heißt IIFE (immediately invoked function expression, ausgesprochen „iffy“)

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

Stellen Sie sicher, dass Sie das vorherige Beispiel genau so eingeben, wie es gezeigt wird (abgesehen von den Kommentaren). Ein IIFE ist ein Funktionsausdruck, der sofort nach seiner Definition aufgerufen wird. Innerhalb der Funktion existiert ein neuer Geltungsbereich, der verhindert, dass tmp global wird. Konsultieren Sie Einführung eines neuen Geltungsbereichs über ein IIFE für Details zu IIFEs.

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

Einzelne Objekte

Wie alle Werte haben Objekte Eigenschaften. Tatsächlich kann man ein Objekt als eine Menge von Eigenschaften betrachten, wobei jede Eigenschaft ein (Schlüssel, Wert)-Paar ist. Der Schlüssel ist eine Zeichenkette, und der Wert ist ein beliebiger JavaScript-Wert.

In JavaScript können Sie einfache Objekte direkt über Objekt-Literale erstellen.

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

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

Das vorhergehende Objekt hat die Eigenschaften name und describe. Sie können Eigenschaften lesen („holen“) und schreiben („setzen“).

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

Funktionswertige Eigenschaften wie describe werden als Methoden bezeichnet. Sie verwenden this, um auf das Objekt zu verweisen, das zur Aufrufung verwendet wurde:

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

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

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

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

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

Der Operator delete entfernt eine Eigenschaft:

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

Beliebige Eigenschaftsschlüssel

Ein Eigenschaftsschlüssel kann eine beliebige Zeichenkette sein. Bisher haben wir Eigenschaftsschlüssel in Objekt-Literalen und nach dem Punkt-Operator gesehen. Sie können sie jedoch nur auf diese Weise verwenden, wenn sie Bezeichner sind (siehe Bezeichner und Variablennamen). Wenn Sie andere Zeichenketten als Schlüssel verwenden möchten, müssen Sie sie in einem Objekt-Literal in Anführungszeichen setzen und eckige Klammern verwenden, um die Eigenschaft zu holen und zu setzen:

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

Eckige Klammern ermöglichen es Ihnen auch, den Schlüssel einer Eigenschaft zu berechnen:

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

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

Extrahieren von Methoden

Wenn Sie eine Methode extrahieren, verliert sie ihre Verbindung zum Objekt. Alleinstehend ist die Funktion keine Methode mehr, und this hat den Wert undefined (im Strict Mode).

Als Beispiel kehren wir zum früheren Objekt jane zurück.

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

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

Wir möchten die Methode describe von jane extrahieren, sie in eine Variable func legen und aufrufen. Das funktioniert jedoch nicht.

> 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. Sie erstellt eine neue Funktion, deren this immer den angegebenen Wert hat:

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

Funktionen innerhalb einer Methode

Jede Funktion hatihre eigene spezielle Variable this. Dies ist unbequem, wenn Sie eine Funktion innerhalb einer Methode verschachteln, da Sie von der Funktion aus nicht auf this der Methode zugreifen können. Das Folgende ist ein Beispiel, bei dem wir forEach mit einer Funktion aufrufen, um ein Array zu durchlaufen:

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);
        });
    }
}

Der Aufruf von logHiToFriends führt zu einem Fehler.

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

Schauen wir uns zwei Möglichkeiten an, dies zu beheben. Erstens könnten wir this in einer anderen Variablen speichern.

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, mit dem Sie einen Wert für this angeben können.

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 Funktionsaufrufen in JavaScript verwendet. Seien Sie immer vorsichtig, wenn Sie von einem dieser Funktionsausdrücke auf this verweisen.

Konstruktoren: Fabriken für Objekte

Bis jetzt denken Sie vielleicht, dass JavaScript-Objekte nur Abbildungen von Zeichenketten zu Werten sind, eine Vorstellung, die durch die Objekt-Literale von JavaScript nahegelegt wird, die wie die Map/Dictionary-Literale anderer Sprachen aussehen. JavaScript-Objekte unterstützen jedoch auch ein Merkmal, das wirklich objektorientiert ist: Vererbung. Dieser Abschnitt erklärt nicht vollständig, wie die Vererbung in JavaScript funktioniert, aber er zeigt ein einfaches Muster, um Ihnen den Einstieg zu erleichtern. Konsultieren SieKapitel 17, wenn Sie mehr erfahren möchten.

Neben der Tatsache, dass sie „echte“ Funktionen und Methoden sind, spielen Funktionen eine weitere Rolle in JavaScript: Sie werden zu Konstruktoren — Fabriken für Objekte —, wenn sie über den Operator new aufgerufen werden. Konstruktoren sind somit ein grobes Analogon zu Klassen in anderen Sprachen. Gemäß Konvention beginnen die Namen von Konstruktoren mit Großbuchstaben. Zum Beispiel:

// 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 richtet die Funktion Point die Instanzdaten ein. Zweitens enthält die Eigenschaft Point.prototype ein Objekt mit den Methoden. Die erstgenannten Daten sind spezifisch für jede Instanz, während die letztgenannten Daten von allen Instanzen gemeinsam genutzt werden.

Um Point zu verwenden, rufen wir es über den Operator new 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 über ganzzahlige Indizes ab Null zugegriffen werden kann.

Arrays haben viele Methoden (siehe Array-Prototypmethoden). 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'

Iterieren über Arrays

Es gibt mehrere Array-Methoden zum Iterieren über Elemente (siehe Array-Iteration). 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 die folgende Ausgabe.

0. a
1. b
2. c

Beachten Sie, dass die Funktion in Zeile (1) Argumente frei ignorieren kann. Sie könnte zum Beispiel nur den Parameter elem haben.

map erstellt ein neues Array, indem es eine Funktion auf jedes Element eines vorhandenen Arrays anwendet:

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

Reguläre Ausdrücke

JavaScript hat integrierte Unterstützung für reguläre Ausdrücke (Kapitel 19 verweist auf Tutorials und erklärt detaillierter, wie sie funktionieren). Sie werden durch Schrägstriche begrenzt:

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

Methode test(): Gibt es eine Übereinstimmung?

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

Methode exec(): Übereinstimmung und Erfassungsgruppen

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

Das zurückgegebene Array enthält die vollständige Übereinstimmung an Index 0, die Erfassung der ersten Gruppe an Index 1 und so weiter. Es gibt eine Möglichkeit (diskutiert in RegExp.prototype.exec: Erfassungsgruppen), diese Methode wiederholt aufzurufen, um alle Übereinstimmungen zu erhalten.

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; andernfalls wird nur das erste Vorkommen ersetzt. Es gibt auch eine Möglichkeit (wie in String.prototype.replace: Suchen und Ersetzen) eine Funktion zu verwenden, um den Ersatz zu berechnen.

Die Standardbibliothek von JavaScript ist relativ spartanisch, aber es gibt mehr Dinge, die Sie verwenden können:

Date (siehe Kapitel 20)
Ein Konstruktor für Daten, dessen Hauptfunktionalität das Parsen und Erstellen von Datumszeichenketten sowie der Zugriff auf die Komponenten eines Datums (Jahr, Stunde usw.) ist.
JSON (siehe Kapitel 22)
Ein Objekt mit Funktionen zum Parsen und Generieren von JSON-Daten.
console.* Methoden (siehe Die Konsolen-API)
Diese browserspezifischen Methoden sind kein Teil der Sprache selbst, aber einige von ihnen funktionieren auch unter Node.js.


[1] Die beiden „Nicht-Werte“ undefined und null haben keine Eigenschaften.

[2] Hinweis: Diese Prüfung meldet Eigenschaften als nicht existent, die tatsächlich existieren, aber den Wert undefined haben.

Weiter: II. Hintergrund