From 4b1a9203c547c019fc5398082ae19a3f3d4c3efe Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:15 -0500 Subject: initial commit --- .../guide/ausdruecke_und_operatoren/index.html | 965 +++++++++++++++++++++ .../javascript/guide/einf\303\274hrung/index.html" | 140 +++ .../guide/feinheiten_des_objektmodells/index.html | 721 +++++++++++++++ .../de/web/javascript/guide/funktionen/index.html | 657 ++++++++++++++ .../guide/grammatik_und_typen/index.html | 699 +++++++++++++++ files/de/web/javascript/guide/index.html | 130 +++ .../guide/indexed_collections/index.html | 448 ++++++++++ .../javascript/guide/keyed_collections/index.html | 157 ++++ .../kontrollfluss_und_fehlerbehandlung/index.html | 430 +++++++++ .../javascript/guide/meta_programming/index.html | 265 ++++++ .../guide/mit_objekten_arbeiten/index.html | 506 +++++++++++ files/de/web/javascript/guide/modules/index.html | 446 ++++++++++ .../javascript/guide/numbers_and_dates/index.html | 378 ++++++++ .../guide/regular_expressions/index.html | 625 +++++++++++++ .../guide/schleifen_und_iterationen/index.html | 337 +++++++ .../javascript/guide/textformatierung/index.html | 257 ++++++ .../web/javascript/guide/using_promises/index.html | 341 ++++++++ 17 files changed, 7502 insertions(+) create mode 100644 files/de/web/javascript/guide/ausdruecke_und_operatoren/index.html create mode 100644 "files/de/web/javascript/guide/einf\303\274hrung/index.html" create mode 100644 files/de/web/javascript/guide/feinheiten_des_objektmodells/index.html create mode 100644 files/de/web/javascript/guide/funktionen/index.html create mode 100644 files/de/web/javascript/guide/grammatik_und_typen/index.html create mode 100644 files/de/web/javascript/guide/index.html create mode 100644 files/de/web/javascript/guide/indexed_collections/index.html create mode 100644 files/de/web/javascript/guide/keyed_collections/index.html create mode 100644 files/de/web/javascript/guide/kontrollfluss_und_fehlerbehandlung/index.html create mode 100644 files/de/web/javascript/guide/meta_programming/index.html create mode 100644 files/de/web/javascript/guide/mit_objekten_arbeiten/index.html create mode 100644 files/de/web/javascript/guide/modules/index.html create mode 100644 files/de/web/javascript/guide/numbers_and_dates/index.html create mode 100644 files/de/web/javascript/guide/regular_expressions/index.html create mode 100644 files/de/web/javascript/guide/schleifen_und_iterationen/index.html create mode 100644 files/de/web/javascript/guide/textformatierung/index.html create mode 100644 files/de/web/javascript/guide/using_promises/index.html (limited to 'files/de/web/javascript/guide') diff --git a/files/de/web/javascript/guide/ausdruecke_und_operatoren/index.html b/files/de/web/javascript/guide/ausdruecke_und_operatoren/index.html new file mode 100644 index 0000000000..7a0e723c6c --- /dev/null +++ b/files/de/web/javascript/guide/ausdruecke_und_operatoren/index.html @@ -0,0 +1,965 @@ +--- +title: Ausdrücke und Operatoren +slug: Web/JavaScript/Guide/Ausdruecke_und_Operatoren +tags: + - Beginner + - Extensions + - Guide + - JavaScript + - Operatoren + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Funktionen", "Web/JavaScript/Guide/Numbers_and_dates")}}
+ +

Dieses Kapitel beschreibt JavaScript Ausdrücke und Operatoren, Zuweisungsoperatoren, Vergleichsoperatoren, Rechenoperatoren, Bit-Operatoren, Logische Operatoren, Operator zur Zeichenkettenverknüpfung, Bedingte (ternäre) Operatoren und mehr.

+ +

Eine vollständige und detaillierte Liste mit Operatoren und Ausdrücken ist in den Referenzen zu finden.

+ +

Operatoren

+ +

JavaScript besitzt verschiedene Operatortypen. Dieser Abschnitt beschreibt die einzelnen Operatoren und beinhaltet Informationen über die Operator-Prioritäten.

+ + + +

JavaScript verfügt über beides, binäre als auch unäre Operatoren. Zudem existiert ein spezieller ternärer Operator - der Bedingungsoperator. Ein binärer Operator benötigt zwei Operanden, einen vor dem Operator und einen nach dem Operator:

+ +
operand1 operator operand2
+
+ +

Zum Beispiel: 3+4, oder x*y.

+ +

Ein unärer Operator erwartet einen einzelnen Operanden, entweder vor, oder nach dem Operator:

+ +
operator operand
+
+ +

oder

+ +
operand operator
+
+ +

Zum Beispiel: x++, oder ++x.

+ +

Zuweisungsoperatoren

+ +

Ein Zuweisungsoperator weißt seinem linken Operanden einen Wert zu. Dieser Wert basiert auf dem Ergebnis des rechten Operanden. Der einfachste Zuweisungsoperator ist das "Gleich" (=), welches den Wert des rechten Operanden dem linken Operanden zuweist.

+ +

Zum Beispiel: x = y (y wid der Wert von x zugewiesen).

+ +

Es gibt auch zusammengesetzte Zuweisungsoperatoren, diese stellen Abkürzungen für die in der folgenden Tabelle aufgelisteten Operationen dar:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Zusammengesetzte Zuweisungsoperatoren
NameAbgekürzter OperatorAusgeschriebener Operator
Zuweisungx = yx = y
Additionx += yx = x + y
Subraktionx -= yx = x - y
Multiplikationx *= yx = x * y
Divisionx /= yx = x / y
Modulo (Division mit Rest)x %= yx = x % y
Exponentiation assignment {{experimental_inline}}x **= yx = x ** y
Left shift assignmentx <<= yx = x << y
Right shift assignmentx >>= yx = x >> y
Unsigned right shift assignmentx >>>= yx = x >>> y
Bitwise AND assignmentx &= yx = x & y
Bitwise XOR assignmentx ^= yx = x ^ y
Bitwise OR assignmentx |= yx = x | y
+ +

Destrukturierung

+ +

Komplexere Zuweisungen ermöglicht Javascript über die sogenannte Destrukturierung. Diese ermöglicht es, Daten aus Arrays oder Objekten mithilfe einer Syntax zu extrahieren, die die Konstruktion von Array- und Objektliteralen widerspiegelt.

+ +
var foo = ["eins", "zwei", "drei"];
+
+// Ohne Destrukturierung
+var eins   = foo[0];
+var zwei   = foo[1];
+var drei   = foo[2];
+
+// mit Destrukturierung
+var [eins, zwei, drei] = foo;
+ +

Vergleichsoperatoren

+ +

Ein Vergleichsoperator vergleicht seine Operanden und gibt einen logischen Wert zurück, der darauf basiert, ob der Vergleich wahr ist, oder nicht.

+ +

Die Operanden können numerische-, string-, logische- oder Objektwerte sein. Zeichenfolgen werden basierend auf der lexikographischen Standardreihenfolge mit unicodewerten verglichen. Wenn die beiden Operanden nicht vom selben Typ sind, versucht JavaScript in den meisten Fällen, sie in einen geeigneten Typ für den Vergleich zu konvertieren. Dieses Verhalten führt im Allgemeinen dazu, dass die Operanden numerisch verglichen werden. Die einzigen Ausnahmen für die Typumwandlung innerhalb von Vergleichen sind die Operatoren === und !==, die strenge Vergleiche durchführen. Diese Operatoren versuchen nicht, die Operanden in kompatible Typen zu konvertieren, bevor sie die Gleichheit überprüfen.

+ +

Die folgende Tabelle beschreibt die Vergleichsoperatoren in Bezug auf diesen Beispielcode:

+ +
var var1 = 3;
+var var2 = 4;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Vergleichsoperatoren
OperatorBeschreibungBeispiele, die true zurückgeben
Equal (==)Gibt true zurück, wenn die Operanden gleich sind.3 == var1 +

"3" == var1

+ 3 == '3'
Not equal (!=)Gibt true zurück, wenn die Operanden ungleich sind.var1 != 4
+ var2 != "3"
Strict equal (===)Gibt true zurück, wenn die Operanden gleich sind und auch der Typ übereinstimmt. Weitere Informationen unter {{jsxref("Object.is")}} und sameness in JS.3 === var1
Strict not equal (!==)Gibt true zurück, wenn die Operanden vom selben Typ sind, doch nicht den selben Wert haben, oder wenn sie den selben Wert haben, doch nicht vom selben Typ sind.var1 !== "3"
+ 3 !== '3'
Greater than (>)Gibt true zurück, wenn der linke Operand größer dem rechten Operanden ist.var2 > var1
+ "12" > 2
Greater than or equal (>=)Gibt true zurück, wenn der linke Operand größer als, oder gleich dem linken Operanden ist.var2 >= var1
+ var1 >= 3
Less than (<)Gibt true zurück, wenn der linke Operand kleiner dem rechten Operanden ist.var1 < var2
+ "2" < 12
Less than or equal (<=)Gibt true zurück, wenn der linke Operand kleiner als, oder gleich dem rechten Operanden ist.var1 <= var2
+ var2 <= 5
+ +
+

Note: (=>) ist kein Operator, hiermit werden Arrow functions notiert.

+
+ +

Arithmetische Operatoren (Rechenzeichen)

+ +

Ein arithmetischer Operator nimmt numerische Werte (Literale oder Variablen) als Operanden entgegen und gibt einen einzelnen numerischen Wert zurück. Die arithmetischen Standardoperatoren sind Addition (+), Subtraktion (-), Multiplikation (*) und Division (/). Diese Operatoren funktionieren wie in den meisten anderen Programmiersprachen, wenn sie mit Fließkommazahlen verwendet werden (beachten Sie insbesondere, dass die Division durch Null {{jsxref ("Infinity")}} ergibt).

+ +
1 / 2; // 0.5
+1 / 2 == 1.0 / 2.0; // this is true
+
+ +

Neben den arithmetischen Standardoperatoren (+, -, * /), stellt JavaScript noch weitere Rechenzeichen zur Verfügung. Diese werden in der folgenden Tabelle aufgeführt:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Arithmetische Operatoren
OperatorBeschreibungBeispiel
Remainder (%)Binärer Operator. Gibt den ganzzahligen Rest der Division beider Operanden zurück.12 % 5 gibt 2 zurück.
Increment (++) +

Unärer Operator. Addiert 1 zu seinem Operanden.

+ +

Wenn der Operator vorangestellt wird (++x), gibt er den Wert seines Operanden zurück nachdem 1 addiert wurde; Wenn der Operator nachgestellt wird (x++), gibt er den Wert seines Operanden zurück, bevor 1 addiert wurde.

+
Wenn x gleich 3 ist, setzt ++x x auf 4 und gibt 4 zurück, wobei x++  3 zurückgibt und erst danach x auf 4 setzt.
Decrement (--) +

Unärer Operator. Subtrahiert 1 von seinem Operanden.

+ +

Der Rückgabewert verhält sich analog zum increment Operator.

+
Wenn x gleich 3 ist, setzt --x x auf 2 und gibt 2 zurück, wobei x-- 3 zurückgibt und erst danach, x auf 2 setzt.
Unary negation (-)Unärer Operator. Gibt die Negierung seines Operanden zurück.Wenn x gleich 3 ist, gibt -x -3 zurück.
Unary plus (+)Versucht, den Operanden in eine Zahl umzuwandeln, wenn dies nicht bereits der Fall ist.+"3" gibt 3 zurück.
+ +true gibt 1 zurück.
Exponentiation operator (**) {{experimental_inline}}Calculates the base to the exponent power, that is, baseexponent2 ** 3 gibt 8 zurück.
+ 10 ** -1 gibt 0.1 zurück.
+ +

Bitweise Operatoren

+ +

Ein bitweiser Operator behandelt seine Operanden als eine Menge von 32 Bits (Nullen und Einsen) und nicht als dezimale, hexadezimale oder oktale Zahlen. Zum Beispiel hat die Dezimalzahl Neun eine binäre Darstellung von 1001. Bitweise Operatoren führen ihre Operationen mit solchen binären Darstellungen aus, doch sie geben standardmäßige numerische JavaScript-Werte zurück.

+ +

Die folgende Tabelle fasst die bitweisen Operatoren von JavaScript zusammen.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bitweise Operatoren
OperatorVerwendungBeschreibung
Bitwise ANDa & bReturns a one in each bit position for which the corresponding bits of both operands are ones.
Bitwise ORa | bReturns a zero in each bit position for which the corresponding bits of both operands are zeros.
Bitwise XORa ^ bReturns a zero in each bit position for which the corresponding bits are the same.
+ [Returns a one in each bit position for which the corresponding bits are different.]
Bitwise NOT~ aInverts the bits of its operand.
Left shifta << bShifts a in binary representation b bits to the left, shifting in zeros from the right.
Sign-propagating right shifta >> bShifts a in binary representation b bits to the right, discarding bits shifted off.
Zero-fill right shifta >>> bShifts a in binary representation b bits to the right, discarding bits shifted off, and shifting in zeros from the left.
+ +

Bitweise logische Operatoren

+ +

Konzeptuell arbeiten bitweise logische Operatoren wie folgt:

+ + + +

Zum Beispiel ist die binäre Darstellung der Zahl neun 1001, die binäre Darstellung der Zahl 15 ist 1111. Wenn die bitweisen logischen Operatoren auf diese Zahlen angewendet werden, ergeben sich folgende Ergebnisse:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Beispiele für bitweise Operatoren
AusdruckErgebnisBinäre Darstellung
15 & 991111 & 1001 = 1001
15 | 9151111 | 1001 = 1111
15 ^ 961111 ^ 1001 = 0110
~15-16~00000000...00001111 = 11111111...11110000
~9-10~00000000...00001001 = 11111111...11110110
+ +

Beachte, dass alle 32 Bits invertiert werden, wenn der bitweise NOT Operator benutzt wird. Wenn dabei das höchstwertigste (ganz linke) Bit auf 1 gesetzt wird, entsteht eine negative Zahl. Note that all 32 bits are inverted using the Bitwise NOT operator, and that values with the most significant (left-most) bit set to 1 represent negative numbers (Zweierkomplement). ~x wird also genauso ausgewertet wie -x - 1.

+ +

Bitweise Schiebeoperatoren

+ +

Die bitweisen Schiebeoperatoren erwarten zwei Operanden. Der erste ist der Wert, der geschoben werden soll, der zweite die Anzahl der Bits, um die geschoben werden soll. Die Richtung, in die geschoben wird, wird durch den verwendeten Operator bestimmt.

+ +

Schiebeoperatoren konvertieren ihre Operanden in 32 Bit Integer Zahlen und liefern als Ergebnis einen Wert vom selben Typen wir der linke Operand.

+ +

Die Schiebeoperatoren sind in der folgenden Tabelle aufgelistet.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bitwise shift operators
OperatorDescriptionExample
Left shift
+ (<<)
This operator shifts the first operand the specified number of bits to the left. Excess bits shifted off to the left are discarded. Zero bits are shifted in from the right.9<<2 yields 36, because 1001 shifted 2 bits to the left becomes 100100, which is 36.
Sign-propagating right shift (>>)This operator shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Copies of the leftmost bit are shifted in from the left.9>>2 yields 2, because 1001 shifted 2 bits to the right becomes 10, which is 2. Likewise, -9>>2 yields -3, because the sign is preserved.
Zero-fill right shift (>>>)This operator shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Zero bits are shifted in from the left.19>>>2 yields 4, because 10011 shifted 2 bits to the right becomes 100, which is 4. For non-negative numbers, zero-fill right shift and sign-propagating right shift yield the same result.
+ +

Logische Operatoren

+ +

Logische Operatoren werden normalerweise mit boolesche (logischen) Werten verwendet - hierbei geben sie dann einen booleschen Wert zurück. Die Operatoren && und || geben den Wert von einem der Operatoren zurück, sodass sie im Falle der Verwendung mit einem nicht-booleschen Wert auch einen nicht-booleschen Wert zurückgeben können. Die logischen Operatoren werden in der folgenden Tabelle beschrieben: 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Logische Operatoren
OperatorVerwendungBeschreibung
Logical AND (&&)expr1 && expr2Gibt expr1 zurück, sofern es zu false konvertiert werden kann; ansonsten wird expr2 zurückgegeben. Insofern mit booleschen Werten verwendet, && gibt true zurück, wenn beide Operanden wahr sind; ansonsten false.
Logical OR (||)expr1 || expr2 +

Gibt expr1 zurück, sofern er zu true konvertiert werden kann. Insofern mit booleschen Werten verwendet, gibt der Operator || true zurück, wenn einer von beiden Operanden true ist; wenn beide false sind, wird false zurückgegeben. 

+
Logical NOT (!)!expr +

Gibt false zurück, wenn sein einziger Operand in true konvertiert werden kann; andernfalls gibt er true zurück. 

+
+ +

Beispiele von Ausdrücken, die in false umgewandelt werden können, sind solche, die null, 0, NaN, einen leeren String ("") oder undefined sind. 

+ +

Die folgenden Zeilen zeigen Beispiele des && (logisches UND) Operators.

+ +
var a1 =  true && true;     // t && t returns true
+var a2 =  true && false;    // t && f returns false
+var a3 = false && true;     // f && t returns false
+var a4 = false && (3 == 4); // f && f returns false
+var a5 = "Cat" && "Dog";    // t && t returns Dog
+var a6 = false && "Cat";    // f && t returns false
+var a7 = "Cat" && false;    // t && f returns false
+
+ +

Die folgenden Zeilen zeigen Beispiele des || (logisches ODER) Operators:

+ +
var o1 =  true || true;     // t || t returns true
+var o2 = false || true;     // f || t returns true
+var o3 =  true || false;    // t || f returns true
+var o4 = false || (3 == 4); // f || f returns false
+var o5 = "Cat" || "Dog";    // t || t returns Cat
+var o6 = false || "Cat";    // f || t returns Cat
+var o7 = "Cat" || false;    // t || f returns Cat
+
+ +

Die folgenden Zeilen zeigen Beispiele des ! (logisches NICHT) Operators:

+ +
var n1 = !true;  // !t returns false
+var n2 = !false; // !f returns true
+var n3 = !"Cat"; // !t returns false
+
+ +

Short-circuit-Bewertung 

+ +

Da logische Ausdrücke von links nach rechts bewertet werden, werden sie auf eine mögliche "Abkürzung" (short-circuit) hin gemäß den folgenden Regeln evaluiert:

+ + + +

Die Regeln der Logik garantieren, dass diese Bewertungen immer korrekt sind. Der irgendwas-Operand werden in den o.g. Beispielen hierbei nicht bewertet. 

+ +

String-Operatoren

+ +

In addition to the comparison operators, which can be used on string values, the concatenation operator (+) concatenates two string values together, returning another string that is the union of the two operand strings.

+ +

For example,

+ +
console.log("my " + "string"); // console logs the string "my string".
+ +

The shorthand assignment operator += can also be used to concatenate strings.

+ +

For example,

+ +
var mystring = "alpha";
+mystring += "bet"; // evaluates to "alphabet" and assigns this value to mystring.
+ +

Conditional (ternary) operator

+ +

The conditional operator is the only JavaScript operator that takes three operands. The operator can have one of two values based on a condition. The syntax is:

+ +
condition ? val1 : val2
+
+ +

If condition is true, the operator has the value of val1. Otherwise it has the value of val2. You can use the conditional operator anywhere you would use a standard operator.

+ +

For example,

+ +
var status = (age >= 18) ? "adult" : "minor";
+
+ +

This statement assigns the value "adult" to the variable status if age is eighteen or more. Otherwise, it assigns the value "minor" to status.

+ +

Comma operator

+ +

The comma operator (,) simply evaluates both of its operands and returns the value of the last operand. This operator is primarily used inside a for loop, to allow multiple variables to be updated each time through the loop.

+ +

For example, if a is a 2-dimensional array with 10 elements on a side, the following code uses the comma operator to update two variables at once. The code prints the values of the diagonal elements in the array:

+ +
var x = [0,1,2,3,4,5,6,7,8,9];
+var a = [x, x, x, x, x]
+
+for (var i = 0, j = 9; i <= j; i++, j--)
+  console.log("a[" + i + "][" + j + "]= " + a[i][j]);
+
+ +

Unary operators

+ +

A unary operation is an operation with only one operand.

+ +

delete

+ +

The delete operator deletes an object, an object's property, or an element at a specified index in an array. The syntax is:

+ +
delete objectName;
+delete objectName.property;
+delete objectName[index];
+delete property; // legal only within a with statement
+
+ +

where objectName is the name of an object, property is an existing property, and index is an integer representing the location of an element in an array.

+ +

The fourth form is legal only within a with statement, to delete a property from an object.

+ +

You can use the delete operator to delete variables declared implicitly but not those declared with the var statement.

+ +

If the delete operator succeeds, it sets the property or element to undefined. The delete operator returns true if the operation is possible; it returns false if the operation is not possible.

+ +
x = 42;
+var y = 43;
+myobj = new Number();
+myobj.h = 4;    // create property h
+delete x;       // returns true (can delete if declared implicitly)
+delete y;       // returns false (cannot delete if declared with var)
+delete Math.PI; // returns false (cannot delete predefined properties)
+delete myobj.h; // returns true (can delete user-defined properties)
+delete myobj;   // returns true (can delete if declared implicitly)
+
+ +
Deleting array elements
+ +

When you delete an array element, the array length is not affected. For example, if you delete a[3], a[4] is still a[4] and a[3] is undefined.

+ +

When the delete operator removes an array element, that element is no longer in the array. In the following example, trees[3] is removed with delete. However, trees[3] is still addressable and returns undefined.

+ +
var trees = ["redwood", "bay", "cedar", "oak", "maple"];
+delete trees[3];
+if (3 in trees) {
+  // this does not get executed
+}
+
+ +

If you want an array element to exist but have an undefined value, use the undefined keyword instead of the delete operator. In the following example, trees[3] is assigned the value undefined, but the array element still exists:

+ +
var trees = ["redwood", "bay", "cedar", "oak", "maple"];
+trees[3] = undefined;
+if (3 in trees) {
+  // this gets executed
+}
+
+ +

typeof

+ +

The typeof operator is used in either of the following ways:

+ +
typeof operand
+typeof (operand)
+
+ +

The typeof operator returns a string indicating the type of the unevaluated operand. operand is the string, variable, keyword, or object for which the type is to be returned. The parentheses are optional.

+ +

Suppose you define the following variables:

+ +
var myFun = new Function("5 + 2");
+var shape = "round";
+var size = 1;
+var today = new Date();
+
+ +

The typeof operator returns the following results for these variables:

+ +
typeof myFun;     // returns "function"
+typeof shape;     // returns "string"
+typeof size;      // returns "number"
+typeof today;     // returns "object"
+typeof dontExist; // returns "undefined"
+
+ +

For the keywords true and null, the typeof operator returns the following results:

+ +
typeof true; // returns "boolean"
+typeof null; // returns "object"
+
+ +

For a number or string, the typeof operator returns the following results:

+ +
typeof 62;            // returns "number"
+typeof 'Hello world'; // returns "string"
+
+ +

For property values, the typeof operator returns the type of value the property contains:

+ +
typeof document.lastModified; // returns "string"
+typeof window.length;         // returns "number"
+typeof Math.LN2;              // returns "number"
+
+ +

For methods and functions, the typeof operator returns results as follows:

+ +
typeof blur;        // returns "function"
+typeof eval;        // returns "function"
+typeof parseInt;    // returns "function"
+typeof shape.split; // returns "function"
+
+ +

For predefined objects, the typeof operator returns results as follows:

+ +
typeof Date;     // returns "function"
+typeof Function; // returns "function"
+typeof Math;     // returns "object"
+typeof Option;   // returns "function"
+typeof String;   // returns "function"
+
+ +

void

+ +

The void operator is used in either of the following ways:

+ +
void (expression)
+void expression
+
+ +

The void operator specifies an expression to be evaluated without returning a value. expression is a JavaScript expression to evaluate. The parentheses surrounding the expression are optional, but it is good style to use them.

+ +

You can use the void operator to specify an expression as a hypertext link. The expression is evaluated but is not loaded in place of the current document.

+ +

The following code creates a hypertext link that does nothing when the user clicks it. When the user clicks the link, void(0) evaluates to undefined, which has no effect in JavaScript.

+ +
Click here to do nothing
+
+ +

The following code creates a hypertext link that submits a form when the user clicks it.

+ +

+Click here to submit
+ +

Relational operators

+ +

A relational operator compares its operands and returns a Boolean value based on whether the comparison is true.

+ +

in

+ +

The in operator returns true if the specified property is in the specified object. The syntax is:

+ +
propNameOrNumber in objectName
+
+ +

where propNameOrNumber is a string or numeric expression representing a property name or array index, and objectName is the name of an object.

+ +

The following examples show some uses of the in operator.

+ +
// Arrays
+var trees = ["redwood", "bay", "cedar", "oak", "maple"];
+0 in trees;        // returns true
+3 in trees;        // returns true
+6 in trees;        // returns false
+"bay" in trees;    // returns false (you must specify the index number,
+                   // not the value at that index)
+"length" in trees; // returns true (length is an Array property)
+
+// built-in objects
+"PI" in Math;          // returns true
+var myString = new String("coral");
+"length" in myString;  // returns true
+
+// Custom objects
+var mycar = { make: "Honda", model: "Accord", year: 1998 };
+"make" in mycar;  // returns true
+"model" in mycar; // returns true
+
+ +

instanceof

+ +

The instanceof operator returns true if the specified object is of the specified object type. The syntax is:

+ +
objectName instanceof objectType
+
+ +

where objectName is the name of the object to compare to objectType, and objectType is an object type, such as {{jsxref("Date")}} or {{jsxref("Array")}}.

+ +

Use instanceof when you need to confirm the type of an object at runtime. For example, when catching exceptions, you can branch to different exception-handling code depending on the type of exception thrown.

+ +

For example, the following code uses instanceof to determine whether theDay is a Date object. Because theDay is a Date object, the statements in the if statement execute.

+ +
var theDay = new Date(1995, 12, 17);
+if (theDay instanceof Date) {
+  // statements to execute
+}
+
+ +

Operator precedence

+ +

The precedence of operators determines the order they are applied when evaluating an expression. You can override operator precedence by using parentheses.

+ +

The following table describes the precedence of operators, from highest to lowest.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operator precedence
Operator typeIndividual operators
member. []
call / create instance() new
negation/increment! ~ - + ++ -- typeof void delete
multiply/divide* / %
addition/subtraction+ -
bitwise shift<< >> >>>
relational< <= > >= in instanceof
equality== != === !==
bitwise-and&
bitwise-xor^
bitwise-or|
logical-and&&
logical-or||
conditional?:
assignment= += -= *= /= %= <<= >>= >>>= &= ^= |=
comma,
+ +

A more detailed version of this table, complete with links to additional details about each operator, may be found in JavaScript Reference.

+ +

Expressions

+ +

An expression is any valid unit of code that resolves to a value.

+ +

Every syntactically valid expression resolves to some value but conceptually, there are two types of expressions: with side effects (for example: those that assign value to a variable) and those that in some sense evaluate and therefore resolve to a value.

+ +

The expression x = 7 is an example of the first type. This expression uses the = operator to assign the value seven to the variable x. The expression itself evaluates to seven.

+ +

The code 3 + 4 is an example of the second expression type. This expression uses the + operator to add three and four together without assigning the result, seven, to a variable.
+
+ JavaScript has the following expression categories:

+ + + +

Primary expressions

+ +

Basic keywords and general expressions in JavaScript.

+ +

this

+ +

Use the this keyword to refer to the current object. In general, this refers to the calling object in a method. Use this either with the dot or the bracket notation:

+ +
this["propertyName"]
+this.propertyName
+
+ +

Suppose a function called validate validates an object's value property, given the object and the high and low values:

+ +
function validate(obj, lowval, hival){
+  if ((obj.value < lowval) || (obj.value > hival))
+    console.log("Invalid Value!");
+}
+
+ +

You could call validate in each form element's onChange event handler, using this to pass it the form element, as in the following example:

+ +

+
+

Enter a number between 18 and 99:

+ +

+ +

Grouping operator

+ +

The grouping operator ( ) controls the precedence of evaluation in expressions. For example, you can override multiplication and division first, then addition and subtraction to evaluate addition first.

+ +
var a = 1;
+var b = 2;
+var c = 3;
+
+// default precedence
+a + b * c     // 7
+// evaluated by default like this
+a + (b * c)   // 7
+
+// now overriding precedence
+// addition before multiplication
+(a + b) * c   // 9
+
+// which is equivalent to
+a * c + b * c // 9
+
+ +

Comprehensions

+ +

Comprehensions are an experimental JavaScript feature, targeted to be included in a future ECMAScript version. There are two versions of comprehensions:

+ +
+
{{experimental_inline}} {{jsxref("Operators/Array_comprehensions", "[for (x of y) x]")}}
+
Array comprehensions.
+
{{experimental_inline}} {{jsxref("Operators/Generator_comprehensions", "(for (x of y) y)")}}
+
Generator comprehensions.
+
+ +

Comprehensions exist in many programming languages and allow you to quickly assemble a new array based on an existing one, for example.

+ +
[for (i of [ 1, 2, 3 ]) i*i ];
+// [ 1, 4, 9 ]
+
+var abc = [ "A", "B", "C" ];
+[for (letter of abc) letter.toLowerCase()];
+// [ "a", "b", "c" ]
+ +

Left-hand-side expressions

+ +

Left values are the destination of an assignment.

+ +

new

+ +

You can use the new operator to create an instance of a user-defined object type or of one of the built-in object types. Use new as follows:

+ +
var objectName = new objectType([param1, param2, ..., paramN]);
+
+ +

super

+ +

The super keyword is used to call functions on an object's parent. It is useful with classes to call the parent constructor, for example.

+ +
super([arguments]); // calls the parent constructor.
+super.functionOnParent([arguments]);
+
+ +

Spread operator

+ +

The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.

+ +

Example: Today if you have an array and want to create a new array with the existing one being part of it, the array literal syntax is no longer sufficient and you have to fall back to imperative code, using a combination of push, splice, concat, etc. With spread syntax this becomes much more succinct:

+ +
var parts = ['shoulder', 'knees'];
+var lyrics = ['head', ...parts, 'and', 'toes'];
+ +

Similarly, the spread operator works with function calls:

+ +
function f(x, y, z) { }
+var args = [0, 1, 2];
+f(...args);
+ +
{{PreviousNext("Web/JavaScript/Guide/Funktionen", "Web/JavaScript/Guide/Numbers_and_dates")}}
diff --git "a/files/de/web/javascript/guide/einf\303\274hrung/index.html" "b/files/de/web/javascript/guide/einf\303\274hrung/index.html" new file mode 100644 index 0000000000..b38cb1b700 --- /dev/null +++ "b/files/de/web/javascript/guide/einf\303\274hrung/index.html" @@ -0,0 +1,140 @@ +--- +title: Einführung +slug: Web/JavaScript/Guide/Einführung +tags: + - Beginner + - Guide + - Introduction + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Introduction +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammatik_und_Typen")}}
+ +

Dieses Kapitel stellt JavaScript vor und behandelt einige grundlegende Konzepte.

+ +

Was solltest du bereits wissen

+ +

Für diese Einführung solltest du die folgenden Grundkenntnisse besitzen:

+ + + +

Wo findest du Informationen zu JavaScript

+ +

Die Dokumentation zu JavaScript im MDN umfasst Folgendes:

+ + + +

Falls du dich das erste Mal mit JavaScript befasst, beginne einfach mit den Tutorials von Learning the Web [de] und dem JavaScript Guide [de]. Sobald du mit den ersten Grundlagen vertraut bist, kannst du die JavaScript Referenz [de] nutzen, um noch mehr über die einzelnen Methoden, Funktionen und Objekte von JavaScript zu erfahren.

+ +

Was ist JavaScript?

+ +

JavaScript ist eine plattformübergreifende, objektorientierte Skriptsprache. Es ist eine kompakte und ressourcenschonende Sprache. Innerhalb einer Host-Umgebung kann JavaScript mit den Objekten seiner Umgebung verknüpft werden, um diese programmatisch zu steuern.

+ +

JavaScript beinhaltet eine Standardbibliothek von Objekten wie Array, Date, und Math, sowie einen Kern an Sprachelementen wie Operatoren, Kontrollstrukturen und Anweisungen. Der JavaScript-Kern kann für eine Vielzahl von Anwendungsfällen erweitert werden, indem man ihn durch zusätzliche Objekte ergänzt. Beispiele:

+ + + +

JavaScript und Java

+ +

JavaScript und Java gleichen einander in manchen Aspekten, sind in anderen aber grundlegend verschieden. Die Sprache JavaScript ähnelt Java, verfügt jedoch nicht über Javas statische Typisierung und seine strenge Typprüfung. JavaScript folgt weitgehend der Ausdruckssyntax, den Namenskonventionen und den elementaren Kontrollstrukturen von Java, was der Grund für die Umbenennung von LiveScript in JavaScript gewesen ist.

+ +

Im Gegensatz zu Javas durch Deklarationen aufgebautes System, von zur Compile-Zeit verfügbaren Klassen, unterstützt JavaScript ein Laufzeitsystem, das auf einer kleinen Zahl an Datentypen basiert, die numerische und Boolesche Werte sowie Zeichenketten repräsentieren. JavaScript besitzt ein prototypen-basiertes Objektmodell anstatt des verbreiteteren klassenbasierten. Das prototypen-basierte Modell liefert dynamische Vererbung; das bedeutet, was vererbt wird, kann zwischen einzelnen Objekten variieren. JavaScript unterstützt zudem Funktionen ohne spezielle deklarative Anforderungen. Funktionen können Objekt Eigenschaften sein, ausgeführt als schwach typisierte Methoden.

+ +

JavaScript ist im Vergleich zu Java eine syntaktisch sehr freie Sprache. Sie müssen nicht alle Variablen, Klassen und Methoden deklarieren. Sie müssen sich nicht damit befassen, ob Methoden öffentlich, privat oder geschützt sind und Sie müssen keine Interfaces implementieren. Variablen, Parameter und Rückgabewerte von Funktionen sind nicht explizit typisiert.

+ +

Java ist eine auf schnelle Ausführung und Typsicherheit ausgelegte, klassenbasierte Programmiersprache. Typsicherheit bedeutet, dass Sie zum Beispiel keine Ganzzal in Java in eine Objektreferenz wandeln oder auf geschützten Speicher zugreifen können, indem Sie den Bytecode von Java manipulieren. Javas klassenbasiertes Modell bedeutet, dass Programme ausschließlich aus Klassen und ihren Methoden bestehen. Javas Klassenvererbung und strenge Typisierung erfordern im Allgemeinen eng gekoppelte Objekthierarchien. Wegen dieser Anforderungen ist das Programmieren in Java komplexer als in JavaScript.

+ +

Im Gegensatz dazu steht JavaScript in der Tradition einer Reihe kleiner, dynamisch typisierter Sprachen wie HyperTalk und dBase. Diese Skriptsprachen stellen, dank ihrer einfacheren Syntax, spezialisierter eingebauter Funktionalität und minimalen Anforderungen, für die Objektgenerierung Programmierwerkzeuge für einen deutlich breiteren Adressatenkreis zu Verfügung.

+ + + + + + + + + + + + + + + + + + + + + + + +
JavaScript im Vergleich zu Java
JavaScriptJava
Objektorientiert. Keine Unterscheidung zwischen Typen von Objekten. Vererbung mittels des Prototypen-Mechanismus, jedes beliebige Objekt kann dynamisch um Eigenschaften und Methoden erweitert werden.Klassenbasiert. Objekte werden in Klassen und Instanzen unterteilt, Vererbung erfolgt vollständig über die Klassenhierarchie. Klassen und Instanzen können keine Eigenschaften und Methoden dynamisch hinzugefügt werden.
Datentypen von Variablen werden nicht deklariert (dynamische Typisierung)Datentypen von Variablen müssen deklariert werden (statische Typisierung)
Kein automatischer Schreibzugriff auf die Festplatte.Kein automatischer Schreibzugriff auf die Festplatte.
+ +

Weitere Informationen zu den Unterschieden zwischen JavaScript und Java finden Sie im Kapitel Einzelheiten des Objektmodells.

+ +

JavaScript und die ECMAScript-Spezifikation

+ +

JavaScript wird durch Ecma International standardisiert — den europäischen Verband zur Standardisierung von Informations- und Telekommunikationssystemen (ECMA war vormals ein Akronym für 'European Computer Manufacturers Association'), um eine standardisierte, internationale Programmiersprache auf der Basis von JavaScript verfügbar zu machen. Diese standardisierte Version von JavaScript, genannt ECMAScript, verhält sich in allen standardkonformen Applikationen identisch. Unternehmen können die offene Sprachdefinition verwenden, um ihre eigene Implementierung von JavaScript zu entwickeln. Der ECMAScript-Standard ist in der Spezifikation ECMA-262 dokumentiert. Unter Neu in JavaScript erfahren Sie mehr über die unterschiedlichen Versionen von JavaScript und den ECMAScript-Spezifikationen.

+ +

ECMA-262 ist auch von der ISO (International Organization for Standardization) als ISO-16262 verabschiedet. Sie finden die Spezifikation auch auf der Website von Ecma International. Die Spezifikation von ECMAScript beschreibt nicht das Document Object Model (DOM), welches durch das World Wide Web Consortium (W3C) und der WHATWG (Web Hypertext Application Technology Working Group) standardisiert wird. Das DOM definiert die Art und Weise, in der HTML-Dokumentenobjekte für Ihr Skript sichtbar sind. Um ein besseres Verständnis der verschiedenen bei der Programmierung in JavaScript eingesetzten Technologien zu entwickeln, lesen Sie den Artikel JavaScript Technologieübersicht.

+ +

JavaScript-Dokumentation vs. ECMAScript-Spezifikation

+ +

Die Spezifikation von ECMAScript besteht aus Anforderungen an eine Implementierung von ECMAScript; sie ist zweckdienlich, falls Sie standardkonforme Spracheigenschaften in Ihrer ECMAScript-Implementierung oder ihrer Laufzeitumgebung (wie SpiderMonkey in Firefox oder v8 in Chrome) realisieren wollen.

+ +

Das ECMAScript-Dokument soll nicht den Skriptprogrammierer unterstützen; nutzen Sie für Informationen zum Erstellen von Skripten die JavaScript-Dokumentation.

+ +

Die ECMAScript-Spezifikation verwendet Terminologie und Syntax, mit der JavaScript-Programmierer möglicherweise nicht vertraut sind. Obwohl sich die Beschreibung der Sprache in ECMAScript unterscheiden kann, bleibt die Sprache selbst die gleiche. JavaScript unterstützt jede Funktionalität, die in der ECMAScript-Spezifikation genannt wird.

+ +

Die JavaScript-Dokumentation beschreibt Aspekte der Sprache in für JavaScript-Programmierer passender Form.

+ +

Erste Schritte mit JavaScript

+ +

Die ersten Schritte mit JavaScript sind einfach: alles was Sie brauchen, ist einen aktuellen Browser. Diese Einführung nimmt auf einige Spracheigenschaften von JavaScript Bezug, die zur Zeit nur in den jüngsten Versionen von Firefox verfügbar sind, somit wird die Nutzung der aktuellsten Firefox-Version empfohlen.

+ +

Es gibt zwei Werkzeuge in Firefox, die zum Experimentieren mit JavaScript nützliche sind: die Web-Konsole and die JavaScript-Umgebung.

+ +

Die Web-Konsole

+ +

Die Web-Konsole zeigt Ihnen Informationen zur aktuell geladenen Webseite an und beinhaltet zudem eine Kommandozeile, die Sie nutzen können, um JavaScript-Ausdrücke im Kontext der aktuellen Seite auszuführen.

+ +

Um die Web-Konsole zu öffnen (Ctrl+Shift+K), wählen Sie "Web-Konsole" im Menü "Entwicklerwerkzeuge", das Sie im Menü von Firefox finden. Die Konsole wird am unteren Rand des Browserfensters angezeigt. Entlang des unteren Randes der Konsole befindet sich die Kommandozeile, in der Sie JavaScript eingeben können; die zugehörige Ausgabe erscheint im darüberliegenden Fensterbereich:

+ +

+ +

JavaScript-Umgebung (Scratchpad)

+ +

Die Web-Konsole eignet sich hervorragend zur Ausführung einzelner Zeilen JavaScript, möchten Sie jedoch mehrere Zeilen ausführen können, ist das nicht besonders komfortabel und Ihren Beispielcode speichern können Sie mit der Web-Konsole auch nicht. Daher ist für komplexere Beispiele die JavaScript-Umgebung die bessere Wahl.

+ +

Um die JavaScript-Umgebung zu öffnen (Shift+F4), wählen Sie "JavaScript-Umgebung" aus dem Menü "Entwicklerwerkzeuge", das Sie im Firefox-Menü finden. Die JavaScript-Umgebung öffnet sich in einem eigenen Fenster als Editor, mit dem Sie JavaScript schreiben und im Browser ausführen können. Sie können auch Skripte auf der Festplatte speichern bzw. laden.

+ +

+ +

Hello world

+ +

Beginnen Sie mit dem Programmieren in JavaScript, indem Sie die JavaScript-Umgebung öffnen und Ihr erstes "Hello World"-Programm in JavaScript schreiben:

+ +
function greetMe(yourName) {
+  alert("Hello " + yourName);
+}
+
+greetMe("World");
+
+ +

Markieren Sie den Quelltext und drücken Sie Ctrl+R, um zu schauen, ob alles funktioniert.

+ +

Auf den folgenden Seiten macht Sie diese Einführung mit Syntax und Spracheigenschaften von JavaScript vertraut, sodass Sie bald komplexere Anwendungen schreiben können.

+ +

{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammatik_und_Typen")}}

diff --git a/files/de/web/javascript/guide/feinheiten_des_objektmodells/index.html b/files/de/web/javascript/guide/feinheiten_des_objektmodells/index.html new file mode 100644 index 0000000000..4d5e46ac26 --- /dev/null +++ b/files/de/web/javascript/guide/feinheiten_des_objektmodells/index.html @@ -0,0 +1,721 @@ +--- +title: Feinheiten des Objektmodells +slug: Web/JavaScript/Guide/Feinheiten_des_Objektmodells +tags: + - Guide + - Intermediate + - JavaScript + - Object + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Mit_Objekten_arbeiten", "Web/JavaScript/Guide/Using_promises")}}
+ +

JavaScript ist eine Objektbasierte Programmiersprache, die auf Prototypen, statt auf Klassen basiert. Aufgrund dieser Tatsache ist es u. U. schwieriger zu erkennen, wie in JavaScript Objekthierarchien erstellt werden und die Vererbung von Eigenschaften und deren Werten erfolgt. Dieses Kapitel versucht diese Situation zu klären.

+ +

Dieses Kapitel geht davon aus, dass bereits Erfahrungen mit JavaScript vorhanden sind und man einfache Objekte mit Funktionen schon erstellt hat.

+ +

Klassenbasierte vs. Prototypbasierte Sprachen

+ +

Klassenbasierte, Objektorientierte Sprachen wie Java und C++ bauen auf dem Konzept von Klassen und Instanzen auf.

+ + + +

Eine Prototypbasierte Sprache wie JavaScript hat diese Unterscheidung nicht: es gibt einfach Objekte. Eine Prototypbasierte Sprache hat die Notation eines prototypischen Objektes, ein Objekt welches als Template genutzt wird und die initialen Eigenschaften für ein neues Objekt vorgibt. Jedes Objekt kann seine eigenen Eigenschaften spezifizieren, entweder beim Erstellen oder zur Laufzeit. Zudem kann jedes Objekt als Prototyp für ein anderes Objekt verwendet werden, was es auch dem zweiten Objekt erlaubt seine Eigenschaften mit dem ersten Objekt zu teilen.

+ +

Eine Klasse definieren

+ +

In einer Klassenbasierten Sprache definiert man Klassen in separaten Klassendefinitionen. In diesen Definitionen spezifiziert man spezielle Methoden, Konstruktoren genannt, um eine Instanz der Klasse zu erstellen. Eine Konstruktormethode spezifiziert Initialwerte für die Eigenschaften einer Instanz und kann andere Prozesse während der Erstellungszeit durchführen. Man benutzt den new Operator in Verbindung mit der Konstruktormethode, um Klasseninstanzen zu erstellen.

+ +

JavaScript folgt einem ähnlichen Modell, jedoch hat keine vom Konstruktor getrennte Klassendefinition. Stattdessen definiert man eine Konstruktorfunktion, um ein Objekt mit einer initialen Menge an Eigenschaften und Werten zu erstellen. Jede JavaScript Funktion kann als Konstruktor verwendet werden. Man benutzt den new Operator mit einer Konstruktorfunktion, um ein neues Objekt zu erstellen.

+ +

Unterklassen und Vererbung

+ +

In einer Klassenbasierten Sprache erstellt man eine Hierarchie von Klassen durch die Klassendefinition. In der Klassendefinition kann man spezifizieren, dass die neue Klasse eine Unterklasse der schon existierenden Klassen ist. Die Unterklasse erbt alle Eigenschaften von der Oberklasse und kann neue Eigenschaften hinzufügen oder vererbte verändern. Angenommen die Employee Klasse hat nur die Eigenschaften name und dept und Manager ist eine Unterklasse von Employee welche die Eigenschaft reports hinzufügt. In diesem Fall hat eine Instanz der Manager Klasse alle drei Eigenschaften: name, dept und reports.

+ +

JavaScript implementiert Vererbung so, dass man jedes Prototypobjekt mit jeder Konstruktorfunktion verbinden kann. So kann man das gleiche EmployeeManager Beispiel erstellen, jedoch mit einer leicht anderen Terminologie. Als erstes definiert man die Employee Konstruktorfunktion, welche die Eigenschaften name und dept spezifiziert. Als nächstes definiert man die Manager Konstruktorfunktion, ruft den Employee Konstruktor auf und spezifiziert die reports Eigenschaft. Letztlich weist man ein neues Objekt zu, welches von Employee.prototype stammt und als prototype für die Manager Konstruktorfunktion dient. Dann, wenn man einen neuen Manager erstellt, erbt dieser die Eigenschaften name und dept von dem Employee Objekt.

+ +

Hinzufügen und Entfernen von Eigenschaften

+ +

In Klassenbasierten Sprachen wird eine Klasse typischerweise zur Übersetzungszeit erstellt und Instanzen dieser Klasse werden zur Übersetzungs- oder Laufzeit instantiiert. Man kann die Anzahl oder die Typen von Eigenschaften einer Klasse nicht nach der Definition der Klasse verändern. In JavaScript kann man immer EIgenschaften während der Laufzeit zu Objekten hinzufügen oder von ihnen entfernen. Wenn eine Eigenschaft zu einem Objekt hinzugefügt wird, welches als Prototyp für andere Objekte fungiert, so bekommen die anderen Objekte auch diese neue Eigenschaft.

+ +

Zusammenfassung von Unterschieden

+ +

Die folgende Tabelle gibt eine kurze Zusammenfassung von einigen der Unterschiede. Der Rest des Kapitels beschreibt detailliert den Einsatz von JavaScript Konstruktoren und Prototypen, um eine Objekthierarchie zu erstellen und vergleicht dieses mit der Sprache Java.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Vergleich von Klassbasierten (Java) und Prototypebasierten (JavaScript) Objektsystemen
Klassenbasiert (Java)Prototypbasiert (JavaScript)
Klassen und Instanzen sind verschiedene Dinge.Alle Objekte können von anderen Objekt erben.
Definieren einer Klasse mit einer Klassendefinition; Instantiieren eine Klasse mit Konstruktormethoden.Definieren und Erstellen einer Menge von Objekten mit Konstruktorfunktionen.
Erstellt ein Objekt mit dem new Operator.Genauso.
Konstruiert eine Objekthierarchie mit Klassendefinitionen, um Unterklasse aus existierenden Klassen zu definieren.Konstruiert eine Objekthierarchie, indem ein Objekt als Prototyp mit einer Konstruktorfunktion verbunden werden.
Erbt Eigenschaften entlang der Klassenkette.Erbt Eigenschaften entlang der Prototypenkette.
Klassendefinitionen spezifizieren alle Eigenschaften von allen Klasseninstanzen. Man kann keine Eigenschaften dynamisch zur Laufzeit hinzufügen.Konstruktorfunktionen oder Prototypen spezifizieren eine initiale Menge von Eigenschaften. Man kann Eigenschaften dynamisch zu individuellen Objekten hinzufügen oder entfernen oder zu einer Menge von Objekten.
+ +

Das Mitarbeiter-Beispiel

+ +

Das restliche Kapitel benutzt die Mitarbeiterhierarchie, die in folgender Grafik dargestellt ist.

+ +
+
+

Eine einfache Objekthierarchie mit den folgenden Objekten:

+ +

+
+ +
+
    +
  • Employee (Mitarbeiter) hat die Eigenschafte name (die als Initialwert einen leerer String hat) und dept (Abteilung) (die als Initialwert "general" hat).
  • +
  • Manager basiert auf Employee. Er fügt die Eigenschaft reports (Berichte) hinzu (die als Initialwert ein leeres Array hat und für ein Array von Employees vorgesehen ist).
  • +
  • WorkerBee (Arbeitsbiene) basiert ebenfalls auf Employee. Er fügt die Eigenschaft projects hinzu (die als Initialwert ein leeres Array hat und für ein Array von Strings vorgesehen ist).
  • +
  • SalesPerson (Verkäufer) basiert auf WorkerBee. Er fügt die Eigenschaft quota (Pensum) hinzu (die als Initialwert 100 hat). zudem überschreibt er die dept Eigenschaft mit dem Wert "sales", um anzudeuten, dass alle Verkäufer in der gleichen Abteilung sind.
  • +
  • Engineer (Ingenieur) basiert auf WorkerBee. Er fügt die Eigenschaft machine (Maschine) hinzu (die als Initialwert einen leeren String hat) und überschreibt die Eigenschaft dept mit dem Wert "engineering".
  • +
+
+
+ +

Erstellen der Hierarchie

+ +

Es gibt viele Wege, um angemessene Konstruktorfunktionen für die Mitarbeiterhierarchie zu implementieren. Welchen man auswählt hängt stark davon ab, was in der Anwendung erreicht werden soll.

+ +

Dieser Abschnitt zeigt, wie man eine sehr einfache (und vergleichbar unflexible) Definition benutzen kann, um zu demonstrieren, wie die Vererbung funktioniert. In dieser Definition ist es nicht möglich jeden Eigenschaftswert zu spezifizieren, wenn ein Objekt erstellt wird. Die neu erstellten Objekte bekommen nur die Initialwerte und können später verändert werden.

+ +

In einer echten Anwendung würde man Konstruktoren so definieren, dass man diesen Eigenschaftswerte zur Erstellzeit übergeben kann (siehe Flexiblere Konstruktoren für mehr Informationen). Für den Anfang zeigen diese Definitionen wie die Vererbung funktioniert.

+ +

Die folgenden Java und JavaScript Employee Definitionen sind gleich. Der einzige Unterschied ist, dass in Java für jede Eigenschaft ein Typ definiert sein muss, in JavaScript jedoch nicht (das liegt daran, dass Java eine stark typisierte Sprache ist, während JavaScript eine schwach typisierte Sprache ist).

+ +
+

JavaScript

+ +
function Employee() {
+  this.name = '';
+  this.dept = 'general';
+}
+
+ +


+ Java

+ +
public class Employee {
+   public String name = "";
+   public String dept = "general";
+}
+
+
+ +

Die Manager und WorkerBee Definitionen zeigen die Unterschiede bei der Spezifizierung eines Oberobjektes in der Vererbungskette. In JavaScript fügt man eine Prototypinstanz der Eigenschaft prototype der Konstruktorfunktion hinzu. Man kann dieses zu jedem Zeitpunkt nach der Definition des Konstruktors machen. In Java spezifiziert man die Oberklasse in der Klassendefinition. Man kann die Oberklasse nicht außerhalb der Klassendefinition ändern.

+ +
+

JavaScript

+ +
function Manager() {
+  Employee.call(this);
+  this.reports = [];
+}
+Manager.prototype =
+    Object.create(Employee.prototype);
+
+function WorkerBee() {
+  Employee.call(this);
+  this.projects = [];
+}
+WorkerBee.prototype =
+    Object.create(Employee.prototype);
+
+ +


+ Java

+ +
public class Manager extends Employee {
+   public Employee[] reports =
+       new Employee[0];
+}
+
+
+
+public class WorkerBee extends Employee {
+   public String[] projects = new String[0];
+}
+
+
+
+
+ +

Die Engineer und SalesPerson Definition erstellt Objekte, welche von WorkerBee und somit auch von Employee abstammen. Ein Objekt von diesen Typen hat alle Eigenschaften der vorherigen Objekte in der Vererbungskette. Zudem überschreiben diese Definitionen den Wert der geerbten dept Eigenschaft mit einem neuen Wert für diese Objekte.

+ +
+

JavaScript

+ +
function SalesPerson() {
+   WorkerBee.call(this);
+   this.dept = 'sales';
+   this.quota = 100;
+}
+SalesPerson.prototype =
+    Object.create(WorkerBee.prototype);
+
+function Engineer() {
+   WorkerBee.call(this);
+   this.dept = 'engineering';
+   this.machine = '';
+}
+Engineer.prototype =
+    Object.create(WorkerBee.prototype);
+
+ +


+ Java

+ +
public class SalesPerson extends WorkerBee {
+   public String dept = "sales";
+   public double quota = 100.0;
+}
+
+
+public class Engineer extends WorkerBee {
+   public String dept = "engineering";
+   public String machine = "";
+}
+
+
+
+ +

Mit diesen Definitionen kann man Instanzen dieser Objekte mit ihren Initialwerten und Eigenschaften erstellen. Die nächste Grafik zeigt diese JavaScript Definitionen, um neue Objekte zu erzeugen und die Werte der neuen Objekte.

+ +
+

Hinweis: Der Term Instanz hat eine spezielle technische Bedeutung in Klassenbasierten Sprachen. In diesen Sprachen ist eine Instanz eine individuelle Instanz von einer Klasse und ist fundamental anders als eine Klasse. In JavaScript gibt es diese technische Bedeutung nicht, weil JavaScript nicht zwischen Klassen und Instanzen unterscheidet. Immer wenn über JavaScript Instanzen gesprochen wird, ist das rein informell und bedeutet, dass ein Objekte mit einer Konstruktorfunktion erstellt wurde. So kann man in diesem Beispiel sagen, dass jane eine Instanz von Engineer ist. Ebenso haben die Terme Eltern, Kind, Vorfahre und Nachfahre keine formale Bedeutung in JavaScript; Man kann diese benutzen, um deutlich zu machen wo sich ein Objekt in der Prototypenkette befindet.

+
+ +

Objekte mit der einfachen Definition erstellen

+ +
+

Objekthierarchie

+ +

Die folgende Hierarchie wird mit dem Code auf der rechten Seite erstellt.

+ +

+ +

Individuelle Objekte = Jim, Sally, Mark, Fred, Jane, etc.
+ "Instanzen" erstellt vom Konstruktor

+ +
var jim = new Employee;
+// Parentheses can be omitted if the
+// constructor takes no arguments.
+// jim.name is ''
+// jim.dept is 'general'
+
+var sally = new Manager;
+// sally.name is ''
+// sally.dept is 'general'
+// sally.reports is []
+
+var mark = new WorkerBee;
+// mark.name is ''
+// mark.dept is 'general'
+// mark.projects is []
+
+var fred = new SalesPerson;
+// fred.name is ''
+// fred.dept is 'sales'
+// fred.projects is []
+// fred.quota is 100
+
+var jane = new Engineer;
+// jane.name is ''
+// jane.dept is 'engineering'
+// jane.projects is []
+// jane.machine is ''
+
+
+ +

Objekteigenschaften

+ +

Dieser Abschnitt diskutiert, wie Objekte EIgenschaften von anderen Objekten in der Prototypenkette erben und was passiert, wenn eine Eigenschaft währende der Laufzeit hinzugefügt wird.

+ +

Eigenschaften vererben

+ +

Es wird vorausgesetzt, dass das Objekt mark als WorkerBee mit dem folgenden Statement erstellt wurde:

+ +
var mark = new WorkerBee;
+
+ +

Wenn JavaScript den new Operator sieht, erstellt es ein neues generisches Objekt und setzt implizit den Wert der internen Eigenschaft [[Prototype]] auf den Wert WorkerBee.prototype und setzt die this Referenz in der WorkerBee Konstruktorfunktion auf das neu erstellte Objekt. Die interne [[Prototype]] Eigenschaft legt die Prototypenkette fest, die zum Zurückgeben von Eigenschaftswerten benutzt wird. Sobald diese Eigenschaften gesetzt sind, gibt JavaScript das neue Objekt zurück und das Zuweisungsstatement setzt die Variable mark mit diesem Objekt.

+ +

Dieser Prozess fügt keine Werte in das mark-Objekt (lokale Werte) für Eigenschaften, die mark von der Prototypenkette erbt. Wenn man nach einem Wert einer Eigenschaft fragt, prüft JavaScript erst, ob der Wert in dem Objekt existiert. Wenn dies der Fall ist, wird dieser zurückgegeben. Wenn kein lokaler Wert vorhanden ist, prüft JavaScript die Prototypenkette (über die interne [[Prototype]] Eigenschaft). Wenn ein Objekt in der Prototypenkette einen Wert für die Eigenschaft hat, wird diese zurückgegeben. Wenn keine solche Eigenschaft gefunden wird, geht JavaScript davon aus, dass das Objekt keine solche Eigenschaft hat. Dementsprechend hat das mark Objekt folgende Eigenschaften und Werte:

+ +
mark.name = '';
+mark.dept = 'general';
+mark.projects = [];
+
+ +

Das mark Objekt hat lokale Werte für die name und dept Eigenschaft über den Employee Konstruktor zugewiesen bekommen. Es wurde ein Wert für die Eigenschaft projects vom WorkerBee Konstruktor zugewiesen. Dieses gibt die Vererbung von Eigenschaften und Werten in JavaScript her. Einige Feinheiten dieses Prozesses werden in Eigenschaftsvererbung erneut besuchen behandelt.

+ +

Weil diese Konstruktoren keine instanzspezifischen Werte bereitstellen können, sind diese Informationen generisch. Die Eigenschaftswerte sind die Standardwerte, die bei der Erstellung aller mit WorkerBee erstellten Objekt genutzt werden. Man kann natürlich die Werte jeder Eigenschaft ändern. So kann man spezifische Informationen für mark wie folgt vergeben:

+ +
mark.name = 'Doe, Mark';
+mark.dept = 'admin';
+mark.projects = ['navigator'];
+ +

Eigenschaften hinzufügen

+ +

In JavaScript kann man zu jedem Objekt zur Laufzeit Eigenschaften hinzufügen. Man ist nicht nur auf die unterstützten Eigenschaften der Konstruktorfunktion angewiesen. Um eine Eigenschaft spezifisch zu einem einfachen Objekt hinzuzufügen, kann man diese wie folgt dem Objekt zuweisen:

+ +
mark.bonus = 3000;
+
+ +

Jetzt hat das mark Objekt eine bonus Eigenschaft, aber kein anderer WorkerBee hat diese Eigenschaft.

+ +

Wenn man eine neue Eigenschaft zu einem Objekt hinzufügt, welches als Prototyp für eine Konstruktorfunktion benutzt wird, fügt man die Eigenschaft zu allen Objekten hinzu, die Eigenschaften von diesem Prototypen erben. Zum Beispiel kann man eine specialty Eigenschaft zu allen employees mit dem folgenden Statement hinzufügen:

+ +
Employee.prototype.specialty = 'none';
+
+ +

Nach der Ausführung dieses Statements durch JavaScript, hat das mark Objekt auch die specialty Eigenschaft mit dem Wert "none". Die folgende Grafik zeigt den Effekt des Hinzufügens dieser Eigenschaft zum Employee Prototyp und das Überschreiben des Engineer Prototypen.

+ +


+ Eigenschaften hinzufügen

+ +

Flexiblere Konstruktoren

+ +

Mit den bisher gezeigten Konstruktorfunktionen kann man beim Erstellen einer Instanz keine Eigenschaftswerte angeben. Wie bei Java kann man Konstruktoren Argumente zum Initialisieren von Eigenschaftswerten für Instanzen übergeben. Die folgende Abbildung zeigt eine Möglichkeit, dies zu tun.

+ +


+ Spezifizieren von Eigenschaften in einem Konstruktor, Teil 1

+ +

Die folgende Tabelle zeigt die Java und JavaScript Definitionen für diese Objekte.

+ +
+

JavaScript

+ +

Java

+
+ +
+
function Employee(name, dept) {
+  this.name = name || '';
+  this.dept = dept || 'general';
+}
+
+ +
public class Employee {
+   public String name;
+   public String dept;
+   public Employee () {
+      this("", "general");
+   }
+   public Employee (String name) {
+      this(name, "general");
+   }
+   public Employee (String name, String dept) {
+      this.name = name;
+      this.dept = dept;
+   }
+}
+
+
+ +
+
function WorkerBee(projs) {
+
+ this.projects = projs || [];
+}
+WorkerBee.prototype = new Employee;
+
+ +
public class WorkerBee extends Employee {
+   public String[] projects;
+   public WorkerBee () {
+      this(new String[0]);
+   }
+   public WorkerBee (String[] projs) {
+      projects = projs;
+   }
+}
+
+
+ +
+
+function Engineer(mach) {
+   this.dept = 'engineering';
+   this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+
+ +
public class Engineer extends WorkerBee {
+   public String machine;
+   public Engineer () {
+      dept = "engineering";
+      machine = "";
+   }
+   public Engineer (String mach) {
+      dept = "engineering";
+      machine = mach;
+   }
+}
+
+
+ +

Diese JavaScript Definitionen benutzen eine spezielle Syntax für das Setzen von Standardwerten:

+ +
this.name = name || '';
+
+ +

Der logische ODER Operator (||) von JavaScript wertet das erste Argument aus. Wenn das Argument zu true konvertiert wird, gibt der Operator dieses zurück. Andernfalls wird der Wert des zweiten Arguments zurückgegeben. Demnach prüft diese Zeile Code, ob name einen nützlichen Wert für die name Eigenschaft hat. Wenn das der Fall ist, wird this.name auf diesen Wert gesetzt. Andernfalls wird this.name auf den leeren String gesetzt. Dieses Kapitel nutzt diese Syntax aus Gründen der Kürze; es kann jedoch auf den ersten Blick verwirrend sein.

+ +
+

Hinweis: Das kann möglicherweise nicht wie erwartet funktionieren, wenn der Konstruktorfunktion Argumente übergeben werden, welche zu false konvertiert werden (wie 0 (null) und der leere String ("")). In diesen Fällen wird der Standardwert benutzt.

+
+ +

Mit dieser Definition, kann man beim Erstellen einer Objektinstanz spezifische Werte für die lokal definierten Eigenschaften benutzen. Man kann das folgende Statement nutzen, um einen neuen Engineer zu erstellen:

+ +
var jane = new Engineer('belau');
+
+ +

Jane's Eigenschaften sind jetzt:

+ +
jane.name == '';
+jane.dept == 'engineering';
+jane.projects == [];
+jane.machine == 'belau';
+
+ +

Zu beachten ist, dass man mit diesen Definitionen keinen Initialwert für vererbte Eigenschaft wie name spezifizieren kann. Wenn man einen Initialwert für vererbe Eigenschaften in JavaScript spezifizieren möchte, muss man mehr Code zum Konstruktor hinzufügen.

+ +

Bisher hat die Konstruktorfunktion ein generisches Objekt erstellt und dann lokale Eigenschaften und Werte für das neue Objekt angegeben. Man kann den Konstruktor weitere Eigenschaften hinzufügen lassen, indem Sie die Konstruktorfunktion für ein Objekt in der Prototypkette direkt aufrufen. Die folgende Abbildung zeigt diese neuen Definitionen.

+ +


+ Spezifizieren von Eigenschaften in einem Konstruktor, Teil 2

+ +

Sehen wir uns eine dieser Definitionen genauer an. Hier ist die neue Definition für den Engineer-Konstruktor:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+ +

Angenommen, man erstellt ein neues Engineer-Objekt wie folgt:

+ +
var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+
+ +

JavaScript folgt folgenden Schritten:

+ +
    +
  1. Der new Operator erstellt ein generisches Objekt und setzt die __proto__ EIgenschaft auf Engineer.prototype.
  2. +
  3. Der new Operator übergibt das neue Objekt dem Engineer Konstruktor als Wert des this Schlüsselwortes.
  4. +
  5. Der Konstruktor erstellt eine neue Eigenschaft namens base für dieses Objekt und weist dieser den Wert des WorkerBee Konstruktors zu. Das macht den WorkerBee Konstruktor zu einer Methode des Engineer Objektes. Der Name der base Eigenschaft ist nicht festgelegt. Man kann jeden legalen Eigenschaftsnamen nutzen; base erinnert einfach an den Zweck.
  6. +
  7. Der Konstruktor ruft die base Methode auf, übergibt als Argumente zwei der Argumente des Konstruktors ("Doe, Jane" und ["navigator", "javascript"]) und zudem den String "engineering". Der explizite Einsatz von "engineering" im Konstruktor zeigt, dass alle Engineer Objekte den selben Wert für dei geerbte dept Eigenschaft haben und dieser Wert den vererbten Wert von Employee überschreibt.
  8. +
  9. Weil base eine Methode von Engineer ist, weshalb JavaScrip beim Aufruf von base das Schlüsselwort this an das erstellte Objekt aus Schritt 1 bindet. Somit übergibt die WorkerBee Funktion die "Doe, Jane" und "engineering" Argumente zu der Employee Konstruktorfunktion. Nach der Rückgabe der Employee Konstruktorfunktion verwendet die WorkerBee Funktion das restliche Argument, um die projects Eigenschaft zu setzen.
  10. +
  11. Nach der Rückgabe der base Methode initialisiert der Engineer Konstruktor die Objekteigenschaft machine mit "belau".
  12. +
  13. Nach der Rückgabe des Konstruktors weist JavaScript das neue Objekte, der jane Variablen zu.
  14. +
+ +

Man kann denken, dass man, nachdem der WorkerBee-Konstruktor innerhalb des Engineer-Konstruktors aufgerufen wird, die Vererbung für das Engineer-Objekte entsprechend eingerichtet hat. Das ist nicht der Fall. Der Aufruf des WorkerBee Konstruktors stellt sicher, dass ein Engineer Objekt mit den Eigenschaften beginnt, die in allen aufgerufenen Konstruktorfunktionen angegeben sind. Wenn jedoch später eine Eigenschaft zum Employee oder WorkerBee Prototyp hinzugefügt wird, wird diese Eigenschaft nicht von Engineer Objekt geerbt. Nimmt man zum Beispiel folgende Statements an:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+Employee.prototype.specialty = 'none';
+
+ +

Das jane Objekt erbt nicht die specialty Eigenschaft. Man muss explizit den Prototypen einstellen, um dynamische Vererbung sicherzustellen. Nimmt man stattdessen folgende Statements an:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+Employee.prototype.specialty = 'none';
+
+ +

Jetzt ist der Wert der specialty Eigenschaft des jane Objektes "none".

+ +

Ein anderer Weg wür Vererbung ist der Einsatz der call() / apply() Methoden. Die folgenden Beispiele sind äquivalent:

+ +
+
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+ +
function Engineer(name, projs, mach) {
+  WorkerBee.call(this, name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+
+ +

Der Einsatz von javascript call() Methode ergibt ein sauberere Implementierung, weil base nicht mehr benötigt wird.

+ +

Eigenschaftsvererbung erneut besuchen

+ +

Im vorangegangenen Abschnitten wurde beschrieben, wie JavaScript Konstruktoren und Prototypen Hierarchien und Vererbung bereitstellt. Dieser Abschnitt diskutiert einige Feinheiten, die in der vorherigen Diskussion nicht unbedingt ersichtlich waren.

+ +

Lokale versus vererbte Werte

+ +

Wenn man auf eine Objekteigenschaft zugreift, führt JavaScript diese Schritte, wie vorhin in dem Kapitel beschrieben, durch:

+ +
    +
  1. Prüft, ob der Wert lokal existiert. Ist das der Fall, wird er zurückgegeben.
  2. +
  3. Wenn kein lokaler Wert vorhanden ist, wird die Prototypenkette (über die __proto__ Eigenschaft) geprüft.
  4. +
  5. Wenn ein Objekt in der Prototypenkette einen Wert für die spezifizierte Eigenschaft hat, wird dieser zurückgegeben.
  6. +
  7. Wenn keine solche Eigenschaft gefunden wird, hat das Objekt diese Eigenschaft nicht.
  8. +
+ +

Das Resultat dieser Schritte hängt davon ab, wie Dinge im Code definiert sind. Das originale Beispiel hat diese Definition:

+ +
function Employee() {
+  this.name = '';
+  this.dept = 'general';
+}
+
+function WorkerBee() {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

Nimmt man mit diesen Definitionen an, man erstellt amy als eine Instanz von WorkerBee mit folgendem Statement:

+ +
var amy = new WorkerBee;
+
+ +

Das amy Objekt hat eine lokale Eigenschaft, projects. Die Werte der name und dept Eigenschaften sind nicht lokal in amy und werden über die Objekteigenschaft __proto__ von amy erreicht. Deshalb hat amy diese Eigenschaftswerte:

+ +
amy.name == '';
+amy.dept == 'general';
+amy.projects == [];
+
+ +

Nimmt man jetzt an, man ändert den Wert der name Eigenschaft in dem Employee Prototyp:

+ +
Employee.prototype.name = 'Unknown';
+
+ +

Auf den ersten Blick erwartet man, dass der neue Wert an alle Instanzen von Employee propagiert wird. Jedoch ist das falsch.

+ +

Wenn man irgendeine Instanz des Employee Objektes erstellt, bekommt die Instanz einen lokalen Wert für die name Eigenschaft (der leere String). Das bedeutet, wenn man den WorkerBee Prototyp mit einem neuen Employee Objekt einstellt, dass WorkerBee.prototype einen lokalen Wert für die name Eigenschaft hat. Wenn demnach JavaScript nach der name Eigenschaft im amy Objekt sucht (eine Instanz von WorkerBee), wird der lokale Wert der Eigenschaft WorkerBee.prototype gefunden. Demnach wird nicht tiefer in der Kette in Employee.prototype gesucht.

+ +

Wenn man den Wert einer Objekteigenschaft zur Laufzeit ändert möchte und den neuen Wert für alle Nachkommenschaften dieses Objektes haben möchte, kann man die Eigenschaft nicht in der Konstruktorfunktion des Objektes definieren. Stattdessen fügt man sie zu dem Konstruktor assoziierten Prototyp hinzu. Angenommen man ändert zum Beispiel deb vorherigen Code wie folgt:

+ +
function Employee() {
+  this.dept = 'general';    // Note that this.name (a local variable) does not appear here
+}
+Employee.prototype.name = '';    // A single copy
+
+function WorkerBee() {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+var amy = new WorkerBee;
+
+Employee.prototype.name = 'Unknown';
+
+ +

In diesem Fall wird die name Eigenschaft von amy "Unknown".

+ +

Das Beispiel zeigt, dass wenn man Standardwerte für Objekteigenschaften haben möchte und zudem dass diese zur Laufzeit geändert werden können, muss man die Eigenschaft im Konstruktorprototypen setzen und nicht in der Konstruktorfunktion.

+ +

Instanzbeziehungen prüfen

+ +

Das Nachgucken von Eigenschaften in JavaScript prüft erst die eigenen Eigenschaften und wenn die Eigenschaft dort nicht ist die Eigenschaften der speziellen Eigenschaft __proto__. Das setzt sich rekursiv fort; der Prozess wird "nachschlagen in der Prototypenkette" genannt.

+ +

Die spezielle Eigenschaft __proto__ wird beim erstellen des Objektes gesetzt; sie wird auf den Wert der prototype Eigenschaft des Konstruktors gesetzt. Deshalb erstellt der Ausdruck new Foo() ein Objekt mit __proto__ == Foo.prototype. Folglich ändert die Änderung der Foo.prototype Eigenschaft alle Nachschlage Prozesse für alle Objekte, die mit new Foo() erstellt wurden.

+ +

Alle Objekte haben eine __proto__ Objekteigenschaft (außer Object); Alle Funktionen haben eine prototype Objekteigenschaft. So können Objekte über 'Prototypenvererbung' mit anderen Objekten verbunden werden. Man kann auf Vererbung testen, indem __proto__ eines Objekts mit einer prototype Objekt einer Funktion verglichen wird. JavaScript hat dafür eine Kurzschreibweise: der instanceof Operator prüft ein Objekt gegen eine Funktion und gibt true zurück, wenn das Objekt von dem Funktionsprototyp erbt. Zum Beispiel:

+ +
var f = new Foo();
+var isTrue = (f instanceof Foo);
+ +

Für ein detailierteres Beispiel nehmen wir an, dass wir die gleichen Definition wie in Eigenschaften vererben haben. Ein Engineer wird wie folgt erstellt:

+ +
var chris = new Engineer('Pigman, Chris', ['jsd'], 'fiji');
+
+ +

Mit diesem Objekt, sind alle folgenden Statements true:

+ +
chris.__proto__ == Engineer.prototype;
+chris.__proto__.__proto__ == WorkerBee.prototype;
+chris.__proto__.__proto__.__proto__ == Employee.prototype;
+chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
+chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
+
+ +

Damit kann man eine instanceOf Funktion wie folgt schreiben:

+ +
function instanceOf(object, constructor) {
+   object = object.__proto__;
+   while (object != null) {
+      if (object == constructor.prototype)
+         return true;
+      if (typeof object == 'xml') {
+        return constructor.prototype == XML.prototype;
+      }
+      object = object.__proto__;
+   }
+   return false;
+}
+
+ +
Hinweis: Die obige Implementierung überprüft den Typ des Objekts gegen "xml", um eine Eigenart der Darstellung von XML-Objekten in neueren JavaScript-Versionen zu umgehen. die wesentlichen Details sind in {{bug(634150)}}, beschrieben.
+ +

Der Einsatz der oben definierten instanceOf Funktion führt bei folgenden Ausdrücken zu true:

+ +
instanceOf(chris, Engineer)
+instanceOf(chris, WorkerBee)
+instanceOf(chris, Employee)
+instanceOf(chris, Object)
+
+ +

Jedoch ist der folgende Ausdruck false:

+ +
instanceOf(chris, SalesPerson)
+
+ +

Globale Informationen in Konstruktoren

+ +

Wenn man einen Konstruktor erstellt, muss man vorsichtig sein, wenn man globale Informationen im Konstruktor einstellt. Nimmt man zum Beispiel an, man möchte eine eindeutige ID, die automatisch für jeden neuen employee zugewiesen wird, kann man die folgende Definition für Employee benutzen:

+ +
var idCounter = 1;
+
+function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   this.id = idCounter++;
+}
+
+ +

Wenn man mit dieser Definition ein neuen Employee erstellt, weist der Konstruktor die nächste ID in der Sequenz zu und inkrementiert dann den globalen ID-Zähler. Wenn die nächsten Statemants die folgenden sind, so ist victoria.id == 1 und harry.id == 2:

+ +
var victoria = new Employee('Pigbert, Victoria', 'pubs');
+var harry = new Employee('Tschopik, Harry', 'sales');
+
+ +

Auf den ersten Blick ist das super. Jedoch wird idCounter jedes mal, wenn ein Employee erstellt wird, wofür auch immer, inkrementiert. Wenn man eine Employee Hierarchie wie im Kapitel oben gezeigt, so wird der Employee Konstruktor für jedes einstellen des Prototypen aufgerufen. Angenommen man hat den folgenden Code:

+ +
var idCounter = 1;
+
+function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   this.id = idCounter++;
+}
+
+function Manager(name, dept, reports) {...}
+Manager.prototype = new Employee;
+
+function WorkerBee(name, dept, projs) {...}
+WorkerBee.prototype = new Employee;
+
+function Engineer(name, projs, mach) {...}
+Engineer.prototype = new WorkerBee;
+
+function SalesPerson(name, projs, quota) {...}
+SalesPerson.prototype = new WorkerBee;
+
+var mac = new Engineer('Wood, Mac');
+
+ +

Angenommen die Definitionen lassen hier die base Eigenschaft weg und rufen den Konstruktor oberhalb in der Prototypenkette auf. In diesem Fall, bekommt das mac Objekt die id 5.

+ +

Abhängig von der Anwendung ist es sinnvoll oder auch nicht, dass der Zähler an diesen Stellen extra hochzählt. Wenn man an dem exakten Wert des Zählers interessiert ist, ist eine mögliche Lösung den folgenden Konstruktor zu nutzen:

+ +
function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   if (name)
+      this.id = idCounter++;
+}
+
+ +

Wenn eine Instanz von Employee erstellt wird, der als Prototyp genutzt wird, übergibt man keine Argumente an den Konstruktor. Benutzt man diese Definition des Konstruktors, wird keine id vergeben und der Zäher nicht aktualisiert, wenn dem Konstruktor keine Argumente übergeben werden. Daraus folgt, dass man einem Employee einen Namen geben muss, damit er eine id erhält. In diesem Beispiel ist mac.id == 1.

+ +

Alternativ kann man WorkerBee eine Kopie des Employee Prototypenobjektes zuweisen:

+ +
WorkerBee.prototype = Object.create(Employee.prototype);
+// instead of WorkerBee.prototype = new Employee
+
+ +

Keine Mehrfachvererbung

+ +

Einige objektorientierte SPrachen erlauben Mehrfachvererbung. Das bedeutet, dass ein Objekt die Eigenschaften und Werte von mehreren Elternobjekte erben kann. JavaScript unterstützt keine Mehrfachvererbung.

+ +

Vererbung von Eigenschafteswerten funktioniert zu JavaScripts Laufzeit durch das Suchen in der Prototypenkette eines Objektes. Weil ein Objekt ein einzigen Prototypen hat, kann JavaScript nicht dynamisch von mehr als einer Prototypenkette erben.

+ +

In JavaScript kann eine Konstruktorfunkton mehrere andere Konstruktorfunktionen in sich aufrufen. Das gibt die Illusion von Mehrfachvererbung. Zum Beispiel die folgenden Statements:

+ +
function Hobbyist(hobby) {
+   this.hobby = hobby || 'scuba';
+}
+
+function Engineer(name, projs, mach, hobby) {
+   this.base1 = WorkerBee;
+   this.base1(name, 'engineering', projs);
+   this.base2 = Hobbyist;
+   this.base2(hobby);
+   this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+
+var dennis = new Engineer('Doe, Dennis', ['collabra'], 'hugo');
+
+ +

Vorausgesetzt wird, die Definition von WorkerBee früher in diesem Kapitel. In diesem Fall hat das dennis Objekt die folgenden Eigenschaften:

+ +
dennis.name == 'Doe, Dennis';
+dennis.dept == 'engineering';
+dennis.projects == ['collabra'];
+dennis.machine == 'hugo';
+dennis.hobby == 'scuba';
+
+ +

dennis hat also die hobby Eigenschaften des Hobbyist Konstruktors bekommen. Setzt man jetzt noch voraus, dass danach Eigenschaften zum Konstruktorprototypen Hobbyist hinzugefügt werde:

+ +
Hobbyist.prototype.equipment = ['mask', 'fins', 'regulator', 'bcd'];
+
+ +

Das dennis Objekt erbt diese neue Eigenschaft nicht.

+ +
{{PreviousNext("Web/JavaScript/Guide/Mit_Objekten_arbeiten", "Web/JavaScript/Guide/Using_promises")}}
diff --git a/files/de/web/javascript/guide/funktionen/index.html b/files/de/web/javascript/guide/funktionen/index.html new file mode 100644 index 0000000000..3eeeb4f4e5 --- /dev/null +++ b/files/de/web/javascript/guide/funktionen/index.html @@ -0,0 +1,657 @@ +--- +title: Funktionen +slug: Web/JavaScript/Guide/Funktionen +tags: + - Beginner + - Functions + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Functions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Schleifen_und_Iterationen", "Web/JavaScript/Guide/Ausdruecke_und_Operatoren")}}
+ +

Funktionen sind ein Grundbaustein in JavaScript. Eine Funktion ist eine Prozedur - eine Reihe von Anweisungen, um eine Aufgabe auszuführen oder eine Wert auszurechnen. Um Funktionen zu verwenden, müssen diese im Scope (Gültigkeitsbereich) deklariert werden, in dem sie ausgeführt werden soll.

+ +

Siehe ebenfalls in der ausführlichen Referenz über JavaScript Funktionen nach, um noch mehr Detail zu erfahren.

+ +

Funktionen definieren

+ +

Funktionsdeklaration

+ +

Eine Funktionsdefinition (auch Funktionsdeklaration oder Funktionsanweisung genannt) besteht aus dem Schlüsselwort function, gefolgt von:

+ + + +

Das folgende Beispiel definiert eine Funktion mit dem Namen square:

+ +
function square(number) {
+  return number * number;
+}
+
+ +

Die Funktion square nimmt einen Parameter entgegen, welcher number heißt. Die Funktion besteht aus einer Anweisung, die besagt, dass der Parameter der Funktion (das ist number), multipliziert mit sich selbst, zurückgegeben werden soll. Dabei gibt das  return Statement an, welcher Wert von der Funktion zurückzugeben wird.

+ +
return number * number;
+
+ +

Bei Primitive Parameter, wie Zahlen, wird der Funktionen der Wert übergeben. Werte, die der Funktion übergeben wurden und innerhalb der Funktion geändert werden, ändert den Wert zwar innerhalb der Funktion, aber nicht global oder in der aufrufenden Funktion.

+ +

Wird ein Objekt als Parameter übergeben (z. B. ein nicht primitiver Wert wie ein  {{jsxref("Array")}} oder ein selbst definiertes Objekt) und die Funktion ändert die Objekteigenschaften, so sind die Änderungen außerhalb der Funktion sichtbar, wie im folgendem Beispiel veranschaulicht wird:

+ +
function myFunc(theObject) {       //Funktiondekleration
+  theObject.make = 'Toyota';
+}
+
+var mycar = {make: 'Honda', model: 'Accord', year: 1998};
+var x, y;
+
+x = mycar.make;  // x bekommt den Wert "Honda"
+
+myFunc(mycar);
+y = mycar.make;  // y  bekommt den Wert "Toyota"
+                 // (die make Eigenschaft wurde in der Funktion geändert)
+ +

Funktionsausdrücke

+ +

Während die Funktionsdeklarationen oben syntaktisch ein Statement sind, kann eine Funktion auch durch Funktionsausdrücke erstellt werde. Derartige Funktionen können auch anonym sein; denn Funktionen benötigten keinen Namen. So kann zum Beispiel die Funktion square auch so definiert werden:

+ +
var square = function(number) { return number * number; };
+var x = square(4); // x bekommt den Wert 16
+ +

Jedoch kann die Funktion auch einen Name haben, um sich innerhalb der Funktion selbst aufzurufen oder die Funktion im Stack Traces des Debuggers zu identifizieren zu können:

+ +
var factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1); };
+
+console.log(factorial(3));
+
+ +

Funktionsausdrücke sind praktisch, um Funktionen als ein Argument einer anderen Funktion zu übergeben. Das folgende Beispiel zeigt die Definition einer map Funktion, die eine Funktion als ersten Parameter erwartet:

+ +
function map(f, a) {
+  var result = [],i; // erstellt ein neues Array
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+  return result;
+}
+
+ +

Im folgenden Quelltext wird einer Funktion eine Funktion übergeben, welche zuvor durch einen Funktions-Ausdruck definiert wurde. Diese Funktion wird für jedes Element in einem Array (zweiter Parameter) ausgeführt.

+ +
function map(f, a) {
+  var result = []; // erstellt ein neues Array
+  var i;
+  for (i = 0; i < a.length; i++) {
+    result[i] = f(a[i]);
+  }
+  return result;
+}
+var f = function(x) {
+  return x * x * x;
+}
+var numbers = [0, 1, 2, 5, 10];
+var cube = map(f,numbers);
+console.log(cube);
+
+ +

gibt [0, 1, 8, 125, 1000]  zurück.

+ +

In JavaScript kann eine Funktion definiert werden, wenn eine Bedingung erfüllt ist. Zum Beispiel wird myFunc nur definiert, wenn num gleich 0 ist:

+ +
var myFunc;
+if (num === 0) {
+  myFunc = function(theObject) {
+    theObject.make = 'Toyota';
+  }
+}
+ +

Im Unterschied zu den hier gezeigten Funktionsdeklarationen, kann man auch den {{jsxref("Function")}} Konstruktor verwenden, um eine Funktion von einem String zur Laufzeit zu erstellen, ähnlich der {{jsxref("eval()")}} Funktion.

+ +

Eine Methode ist eine Funktion, die Eigenschaft eines Objektes ist. Mehr Informationen über Objekt und Methoden sind im Artikel "Mit Objekten arbeiten" zu finden.

+ +

Aufruf von Funktionen

+ +

Das Definieren einer Funktion führen diese noch nicht aus. Die Definition gibt der Funktion lediglich einen Namen und beschreibt was geschehen soll, wenn die Funktion aufgerufen wird. Erst der Aufruf ermöglicht es die Aktionen mit den angegebenen Parametern durchzuführen. Zum Beispiel wird die vorher definierte Funktion square so aufgerufen:

+ +
square(5);
+
+ +

Es wird die Funktion mit dem Argument 5 aufgerufen. Die Funktion führt ihre Anweisungen aus und gibt den Wert 25 zurück.

+ +

Funktionen müssen im Scope (Gültigkeitsbereich) sein, wenn sie aufgerufen werden, können jedoch auch erst später definiert werden, wie im folgenden Beispiel:

+ +
console.log(square(5));
+/* ... */
+function square(n) { return n * n; }
+
+ +

Der Scope einer Funktion ist die Funktion in der sie deklariert wird, oder das gesamte Programm, falls sie auf oberster Ebene deklariert wird.

+ +
+

Hinweis: Nur die oben angegebene Syntax für Funktionen wird funktionieren (function funcName(){}). Der folgende Code funktioniert nicht. Das bedeutet, dass das nur mit Funktionsdeklarationen funktioniert aber nicht mit Funktionsausdrücken.

+
+ +
console.log(square); // square ist mit dem Initialwert undefined gehoisted.
+console.log(square(5)); // TypeError: square is not a function
+var square = function(n) {
+  return n * n;
+}
+
+ +

Die Argumente einer Funktion sind nicht auf Strings und Nummern limitiert, denn es können auch ganze Objekte übergeben werden. Die showProps() Funktion (definiert in Beitrag "Arbeiten mit Objekten") ist ein Beispiel für einer Funktion, die Objekte als Argument entgegennimmt.

+ +

Eine Funktion kann sich selbst Aufrufen. Zum Beispiel berechnet folgende Funktion die Fakultät rekursiv:

+ +
function factorial(n) {
+  if ((n === 0) || (n === 1))
+    return 1;
+  else
+    return (n * factorial(n - 1));
+}
+
+ +

Die Fakultät von 1 bis 5 kann wie folgt berechnet werden:

+ +
var a, b, c, d, e;
+a = factorial(1); // a wird der Wert 1 zugewiesen
+b = factorial(2); // b wird der Wert 2 zugewiesen
+c = factorial(3); // c wird der Wert 6 zugewiesen
+d = factorial(4); // d wird der Wert 24 zugewiesen
+e = factorial(5); // e wird der Wert 120 zugewiesen
+
+ +

Es gibt aber noch weitere Möglichkeiten Funktionen aufzurufen. Oftmals gibt es Fälle, in denen Funktionen dynamisch aufgerufen werden müssen, die Anzahl der Argumente variiert oder der Kontext einer Funktion zur Laufzeit gesetzt werden muss. Das zieht nach sich, dass Funktionen selbst Objekte sind, die Methoden haben (siehe das {{jsxref("Function")}} Objekt). Eine diese Methoden ist die {{jsxref("Function.apply", "apply()")}} Methode, mit der man die oben genannten Aufgaben lösen kann.

+ +

Scopes (Gültigkeitsbereiche) von Funktionen

+ +

Variablen, die in einer Funktion definiert werden, können nicht außerhalb der Funktion erreicht werden, weil die Variablen nur im Scope (Gültigkeitbereich) der Funktion definiert sind. Im Gegensatz dazu kann eine Funktion alle Variablen und Funktionen erreichen, die in dem Scope definiert wurden, in dem auch die Funktion definiert wurde. Anders gesagt kann eine Funktion, die im globalen Scope definiert wurde, alle Variablen und Funktionen des globalen Scopes erreichen. Wenn eine Funktion in einer Funktion definiert wird, kann die innere Funktion auf alle Definitionen seiner Elternfunktion und alle Definitionen, auf die die Elternfunktion Zugriff hat, zugreifen.

+ +
// Die folgenden Variablen sind im globalen Scope definiert
+var num1 = 20,
+    num2 = 3,
+    name = 'Chamahk';
+
+// Diese Funktion ist im globalen Scope definiert
+function multiply() {
+  return num1 * num2;
+}
+
+multiply(); // gibt 60 zurück
+
+// Ein Beispiel für verschachtelte Funktionen
+function getScore() {
+  var num1 = 2,
+      num2 = 3;
+
+  function add() {
+    return name + ' scored ' + (num1 + num2);
+  }
+
+  return add();
+}
+
+getScore(); // gibt "Chamahk scored 5" zurück
+
+ +

Scope und der Funktionsstack

+ +

Rekursion

+ +

Eine Funktion kann sich selbst referenzieren und aufrufen. Dabei gibt es drei Möglichkeiten, wie eine Funktion sich selbst referenzieren kann:

+ +
    +
  1. Der Funktionsname
  2. +
  3. arguments.callee
  4. +
  5. Eine im Scope liegende Variable, die auf die Funktion referenziert.
  6. +
+ +

Nimmt man zum Beispiel folgende Funktion:

+ +
var foo = function bar() {
+   // Anweisungen
+};
+
+ +

Folgende Anweisungen im Körper der Funktion bewirken alle das Gleiche:

+ +
    +
  1. bar()
  2. +
  3. arguments.callee()
  4. +
  5. foo()
  6. +
+ +

Eine Funktion, die sich selbst aufruft, wird rekursive Funktion genannt. Rekursion ist dabei vergleichbar mit einer Schleife. Beide führen den selben Quelltext mehrfach aus und beide benötigen eine Bedingung (um eine unendliche Schleife zu vermeiden oder eine unendliche Rekursion zu vermeiden). Das nächste Beispiel zeigt eine Schleife:

+ +
var x = 0;
+while (x < 10) { // "x < 10" ist die Schleifenbedingung
+   // do stuff
+   x++;
+}
+
+ +

Diese Schleife kann in eine rekursive Funktion konvertiert werden, die aufgerufen wird:

+ +
function loop(x) {
+  if (x >= 10) // "x >= 10" ist die Abbruchbedingung (gleich zu "!(x < 10)")
+    return;
+  // do stuff
+  loop(x + 1); // der rekursive Aufruf
+}
+loop(0);
+
+ +

Jedoch können manche Algorithmen nicht in eine einfache Schleife umgewandelt werden. Zum Beispiel kann das Abrufen aller Knoten einer Baumstruktur (z. B. DOM) einfacher rekursiv realisieren werden:

+ +
function walkTree(node) {
+  if (node == null) //
+    return;
+  // do something with node
+  for (var i = 0; i < node.childNodes.length; i++) {
+    walkTree(node.childNodes[i]);
+  }
+}
+
+ +

Verglichen mit der Funktion loop, erzeugt hier jeder rekursive Aufruf mehrere weitere rekursive Aufrufe.

+ +

Es ist möglich jeden rekursiven Algorithmus in einen nicht rekursiven umzuwandeln, jedoch ist die Logik oftmals sehr viel komplexer und es wird ein zusätzlicher Stack benötigt. Rekursion nutzt ebenfalls einen Stack: den Funktionsstack.

+ +

Die Stack-ähnliche Funktionsweise kann in folgendem Beispiel betrachtet werden:

+ +
function foo(i) {
+  if (i < 0)
+    return;
+  console.log('begin:' + i);
+  foo(i - 1);
+  console.log('end:' + i);
+}
+foo(3);
+
+// Output:
+
+// begin: 3
+// begin: 2
+// begin: 1
+// begin: 0
+// end: 0
+// end: 1
+// end: 2
+// end: 3
+ +

Verschachtelte Funktionen und Closures

+ +

Man kann eine Funktion in eine andere verschachteln. Die verschachtelte (innere) Funktion ist privat innerhalb ihrer Containerfunktion (äußere Funktion). Sie formt auch eine Closure. Eine Closure ist ein Ausdruck, der freie Variablen enthalten kann, (typischerweise eine Funktion) zusammen mit einer Umgebung, welche die diese Variablen einschließt (und damit den Ausdruck abschließt, daher der Name closure).

+ +

Weil eine verschachtelte Funktion eine Closure ist, bedeutet das, dass sie die Argumente und Variablen ihrer Containerfunktion vererbt bekommt. Anders gesagt enthält der Scope der inneren Funktion den Scope der äußeren Funktion.

+ +

Zusammenfassend:

+ + + +

Im folgenden Beispiel werden innere Funktionen gezeigt:

+ +
function addSquares(a, b) {
+  function square(x) {
+    return x * x;
+  }
+  return square(a) + square(b);
+}
+a = addSquares(2, 3); // gibt 13 zurück
+b = addSquares(3, 4); // gibt 25 zurück
+c = addSquares(4, 5); // gibt 41 zurück
+
+ +

Weil die innere Funktion eine Closure formt, kann die äußere Funktion aufgerufen werden und Argumente für die innere und äußere Funktion spezifizieren::

+ +
function outside(x) {
+  function inside(y) {
+    return x + y;
+  }
+  return inside;
+}
+fn_inside = outside(3);  // Man kann sich das folgendermaßen vorstellen
+                         // gib mir eine Funktion, die 3 zu einem Parameter addiert.
+result = fn_inside(5);   // gibt 8 zurück
+
+result1 = outside(3)(5); // gibt 8 zurück
+
+ +

Erhaltung von Variablen

+ +

Bemerkenswert ist, dass x erhalten wird, wenn inside zurückgegeben wird. Eine Closure muss alle Argumente und Variablen erhalten, die sie referenziert. Weil jeder Aufruf potenziell verschiedene Argumente benötigt, wird eine neue Closure für jeden Aufruf erstellt. Der Speicher kann nur freigegeben werden, wenn die zurückgegebene inside Funktion nicht mehr erreichbar ist.

+ +

Das ist nicht anders mit gespeicherten Referenzen in anderen Objekten, jedoch oftmals weniger deutlich, weil man diese nicht direkt referenziert und nicht inspizieren kann.

+ +

Mehrfach verschachtelte Funktionen

+ +

Funktionen können mehrfach verschachtelt sein, z. B. eine Funktion (A) enthält eine Funktion (B), die eine Funktion (C) enthält. Beide Funktionen, B und C sind Closures, B kann A erreichen und C kann B erreichen. Zudem kann C auch A erreichen, weil C B erreichen kann und B A erreichen kann. Deswegen kann eine Closure mehrere Scopes enthalten.; sie enthält rekursiv die Scopes der Funktion, die der Container ist. Das wird Scopeverkettung (scope chaining) genannt.

+ +

Untersuche das nächste Beispiel:

+ +
function A(x) {
+  function B(y) {
+    function C(z) {
+      console.log(x + y + z);
+    }
+    C(3);
+  }
+  B(2);
+}
+A(1); // logs 6 (1 + 2 + 3)
+
+ +

In diesem Beispiel benutzt C die Variablen y, von B, und x, von A. Das kann gemacht werden weil:

+ +
    +
  1. B ist eine Closure, die A enthält, z. B. B kann die Argumente und Variablen von A benutzen.
  2. +
  3. C ist ein Closure, die B enthält.
  4. +
  5. Weil die Closure von B auf A zugreifen kann, kann die Closure von C auf die Argumente und Variablen von A und B zugreifen. Anders gesagt verkettet C den Scope von B und A in dieser Reihenfolge.
  6. +
+ +

Das umgekehrte ist nicht möglich. A kann nicht auf C zugreifen, weil A nicht auf die Variablen und Argumente von B zugreifen kann und C eine Variable von B ist. So bleibt C für B privat.

+ +

Namenskonflikte

+ +

Wenn zwei Argumente oder Variablen in dem Scope einer Closure mit dem gleichen Namen existieren, gibt es einen Namenskonflikt. Der innerste Scope hat dann Vorrang, was bedeutet, dass der innerste Scope die höchste Priorität hat, während der äußerste Scope die geringste Priorität hat. Das ist wegen der Scopeverkettung. Das erste Glied in der Kette ist der innerste Scope und das letzt Glied ist der äußerste Scope. Dieses ist im folgenden Beispiel zu sehen:

+ +
function outside() {
+  var x = 10;
+  function inside(x) {
+    return x;
+  }
+  return inside;
+}
+result = outside()(20); // gibt 20 statt 10 zurück
+
+ +

Der Namenskonflikt tritt beim der Anweisung return x auf und ist zwischen dem Parmeter x von inside und der Variable x von outside. Die Scopekette ist hier {inside, outside, globales Objekt}. Dabei bekommt x von inside eine höhere Priorität als das x von outside. und 20 wird statt der 10 zurückgegeben.

+ +

Closures

+ +

Closures sind eines der mächtigsten Funktionen von JavaScript. JavaScript unterstützt das Verschachteln von Funktionen und erlaubt der inneren Funktionen den vollen Zugriff auf alle definierten Variablen und Funktionen der äußeren Funktion (und alle anderen Variablen und Funktionen die die äußere Funktion erreichen kann). Jedoch hat die äußere Funktion keinen Zugriff auf die Variablen und Funktione, die in der innere Funktion definiert werden. Das unterstützt mehr oder weniger Sicherheit für die Variablen der inneren Funktion. Wenn die innere Funktion Zugriff auf den Scope der äußeren Funktion hat, müssen die Variablen und Funktionen der äußeren Funktion länger leben, als die Ausführungen der inneren Funktion, weil die innere Funktion das Überleben der äußeren Funktion managet. Eine Closure wird erstellt, wenn die innere Funktion irgendwie in einem äußeren Scope der äußeren Funktion erreichbar gemacht wird.

+ +
var pet = function(name) {   // Die äußere Funktion definiert eine Variable "name"
+  var getName = function() {
+    return name;             // Die innere Funktion hat Zugriff auf die "name" Variable der äußeren Funktion
+  }
+  return getName;            // gibt die innere Funktion zurück
+}
+myPet = pet('Vivie');
+
+myPet();                     // gibt "Vivie" zurück
+
+ +

Es kann viel komplexer sein, als der oben gezeigte Quelltext. Ein Objekt enthält Methoden zum verändern von inneren Variablen der äußeren Funktion.

+ +
var createPet = function(name) {
+  var sex;
+
+  return {
+    setName: function(newName) {
+      name = newName;
+    },
+
+    getName: function() {
+      return name;
+    },
+
+    getSex: function() {
+      return sex;
+    },
+
+    setSex: function(newSex) {
+      if(typeof newSex === 'string' && (newSex.toLowerCase() === 'male' || newSex.toLowerCase() === 'female')) {
+        sex = newSex;
+      }
+    }
+  }
+}
+
+var pet = createPet('Vivie');
+pet.getName();                  // Vivie
+
+pet.setName('Oliver');
+pet.setSex('male');
+pet.getSex();                   // male
+pet.getName();                  // Oliver
+
+ +

Im Quelltext oben ist die name Variable der äußeren Funktion in den inneren Funktionen erreichbar und es gibt keine andere Möglichkeit die inneren Variablen zu erreichen, als über die inneren Funktion. Die innere Variable der inneren Funktion fungiert als sicherer Speicher für die äußeren Parameter und Variablen. Sie enthalten permanent und sicher die Daten mit denen die innere Funktion arbeitet. Die Funktion hat niemals eine Variable beschrieben noch hat sie einen Namen.

+ +
var getCode = (function() {
+  var secureCode = '0]Eal(eh&2';    // Ein Code der nicht von Außerhalb verändert werden soll
+
+  return function () {
+    return secureCode;
+  };
+}());
+
+getCode();    // gibt secureCode zurück.
+
+ +

Es gibt aber eine menge von Tücken, die der Einsatz von Closures mit sich bringt. Wenn eine innere Funktion eine Variable definiert, die den gleichen Namen wie eine Variable im äußeren Scope hat, kann die äußere Variable nicht mehr referenziert werden.

+ +
var createPet = function(name) {  // Äußere Funktion definiert die Variable "name"
+  return {
+    setName: function(name) {    // Innere Funktion definiert ebenfalls eine Variable "name"
+      name = name;               // Wie referenziert man die Variable "name" der äußeren Funktion?
+    }
+  }
+}
+
+ +

Einsatz des arguments Objekts

+ +

Die Argumente einer Funktion werden in einem Array-ähnlichen Objekt gewartet. In einer Funktion können die Argumente wie folgt adressiert werden:

+ +
arguments[i]
+
+ +

i ist die Ordnungsnummer des Arguments, beginnend bei null. So ist das erste übergebene Argument einer Funktion arguments[0]. Die Anzahl der übergebenen Argumente ist arguments.length.

+ +

Mit dem arguments Objekt kann man eine Funktion mit mehr Agumenten aufrufen als sie formal deklariert wurden. Das ist oft nützlich, wenn man nicht weiß, wie viele Argumente einer Funktion übergeben werden. Mit arguments.length kann die Anzahl der Argumente, die einer Funktion übergeben wurde, ermittelt werden. Über das arguments Objekt können dann alle Argumente gelesen werden.

+ +

Zum Beispiel kann es eine Funktion geben, die verschieden viele Strings zusammenfügt. Das einzige formale Argument der Funktion ist das Trennzeichen, welches die Zeichen definiert, die zwischen den Strings eingefügt werden. Im folgenden Quelltext ist die Funktion implementiert:

+ +
function myConcat(separator) {
+   var result = ''; // initialize list
+   var i;
+   // iterate through arguments
+   for (i = 1; i < arguments.length; i++) {
+      result += arguments[i] + separator;
+   }
+   return result;
+}
+
+ +

Man kann der Funktion jede Anzahl an Argumenten übergeben und die Funktion fügt die Argumente in einem String zusammen:

+ +
// returns "red, orange, blue, "
+myConcat(', ', 'red', 'orange', 'blue');
+
+// returns "elephant; giraffe; lion; cheetah; "
+myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
+
+// returns "sage. basil. oregano. pepper. parsley. "
+myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
+
+ +
+

Hinweis: Die arguments Variable ist "Array-ähnlich", aber kein Array. Es ist Array-ähnlich indem es nummerierte Indizes und eine length Eigenschaft hat. Jedoch unterstützt es nicht alle Array-Manipulations-Methoden.

+
+ +

Siehe im {{jsxref("Function")}} Objekt in den JavaScript Referenzen für mehr Informationen.

+ +

Funktionsparameter

+ +

Mit ECMAScript 2015, gibt es zwei neue Arten von Parametern: Default-Parameter und Rest-Parameter.

+ +

Default-Parameter

+ +

In JavaScript ist der Standardwert eines Parameters undefined. In manchen Situationen ist es sinnvoll den Standardwert auf einen anderen Wert zu setzen. Das ist das Einsatzgebiet von Default-Parametern.

+ +

In der Vergangenheit war die Strategie für das Setzen von Standardwerten, dass im Körper der Funktion geprüft wird, ob ein Parameter undefined ist und ihn in diesem Fall neu zu beschreiben. Wenn im folgenden Beispiel kein Argument b übergeben wird, wird dieser undefined sein und die Auswertung von a*b wird NaN sein. Deswegen ist dieser Fall in der zweiten Zeile des Beispiels abgefangen:

+ +
function multiply(a, b) {
+  b = typeof b !== 'undefined' ?  b : 1;
+
+  return a * b;
+}
+
+multiply(5); // 5
+
+ +

Mit Default-Parametern ist die Überprüfung im Körper der Funktion nicht mehr nötig. Jetzt kann man 1 als Standardwert für b im Funktionskopf angeben:

+ +
function multiply(a, b = 1) {
+  return a * b;
+}
+
+multiply(5); // 5
+ +

Für mehr Details, siehe in den Referenzen unter Default-Parameter.

+ +

Rest-Parameter

+ +

Die Rest-Parameter Syntax ermöglicht er eine unendliche Anzahl von Argumenten als Array zu repräsentieren. Im Beispiel wird der Rest-Parameter eingesetzt um die alle Argumente ab dem zweiten Argument zu sammeln. Danach werden diese mit dem ersten Parameter multipliziert. Dieses Beispiel benutzt Pfeilfunktionen, welche in nächsten Kapitel erklärt werden:

+ +
function multiply(multiplier, ...theArgs) {
+  return theArgs.map(x => multiplier * x);
+}
+
+var arr = multiply(2, 1, 2, 3);
+console.log(arr); // [2, 4, 6]
+ +

Pfeilfunktionen

+ +

Ein Pfeilfunktions Ausdruck hat eine kürzere Syntax verglichen mit Funktionsausdrücken und bindet lexikalisch den this Wert. Pfeilfunktionen sind immer anonym. Sie dazu auch den hacks.mozilla.org Blogbeitrag: "ES6 In Depth: Arrow functions".

+ +

Zwei Faktoren haben die Einführung von Pfeilfunktionen beeinflusst: kürzere Funktionen und lexikalisches this.

+ +

Kürzere Funktionen

+ +

In manchen funktionalen Patterns sind kurze Funktionen willkommen. Vergleiche:

+ +
var a = [
+  'Hydrogen',
+  'Helium',
+  'Lithium',
+  'Beryl­lium'
+];
+
+var a2 = a.map(function(s) { return s.length; });
+
+console.log(a2); // logs [8, 6, 7, 9]
+
+var a3 = a.map( s => s.length );
+
+console.log(a3); // logs [8, 6, 7, 9]
+
+ +

Lexikalisches this

+ +

Bis es Pfeilfunktionen gab, hat jede neue Funktion sein eigenen this Wert definiert (ein neues Objekt in Fällen eines Konstruktors, undefined in Funktionsaufrufen im strict mode, das Kontextobjekt, wenn eine Funktion als Objektmethode aufgerufen wird, etc.). Das ist lästig mit objektorientierten Programmierstilen.

+ +
function Person() {
+  // The Person() constructor defines `this` as itself.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // In nonstrict mode, the growUp() function defines `this`
+    // as the global object, which is different from the `this`
+    // defined by the Person() constructor.
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+ +

In ECMAScript 3/5, wurde dieses Problem behoben, indem der Wert der Variablen this in einer weiteren Variablen gespeichert wird.

+ +
function Person() {
+  var self = this; // Some choose `that` instead of `self`.
+                   // Choose one and be consistent.
+  self.age = 0;
+
+  setInterval(function growUp() {
+    // The callback refers to the `self` variable of which
+    // the value is the expected object.
+    self.age++;
+  }, 1000);
+}
+ +

Alternativ kann eine gebundene Funktion  erstellt werden, so dass der Wert für this mit übergeben werden kann.

+ +

Pfeilfunktionen nutzen den this Wert des umschließenden Kontextes, so dass der folgende Quelltext wie erwartet funktioniert:

+ +
function Person() {
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // |this| properly refers to the person object
+  }, 1000);
+}
+
+var p = new Person();
+ +

Vordefinierte Funktionen

+ +

JavaScript hat einige eingebaute Funktionen:

+ +
+
{{jsxref("Global_Objects/eval", "eval()")}}
+
+

Die eval() Methode wertet JavaScript Quelltext repräsentiert als String aus.

+
+
{{jsxref("Global_Objects/uneval", "uneval()")}} {{non-standard_inline}}
+
+

Die uneval() Methode erstellt einen String der Quelltext eines {{jsxref("Object")}}s repräsentiert.

+
+
{{jsxref("Global_Objects/isFinite", "isFinite()")}}
+
+

Die globale isFinite() Funktion ob ein übergebener Wert endlich ist. Der übergebene Wert wird, wenn es nötig ist, zu einer Zahl konvertiert.

+
+
{{jsxref("Global_Objects/isNaN", "isNaN()")}}
+
Die isNaN() Funktion überprüft, ob ein Wert {{jsxref("Global_Objects/NaN", "NaN")}} ist oder nicht. Hinweis: Wegen einigen Zwängen innerhalb der isNaN Funktion gibt es interessante Regeln; alternativ kann auch die in  ECMAScript 2015 definierte Funktion Funktion {{jsxref("Number.isNaN()")}} oder der Operator typeof verwendet werden, um einen {{jsxref("Global_Objects/NaN", "NaN")}} Wert zu erkennen.
+
{{jsxref("Global_Objects/parseFloat", "parseFloat()")}}
+
+

Doe parseFloat() Funktion liest einen String als Argument ein und gibt eine Gleitkommazahl zurück.

+
+
{{jsxref("Global_Objects/parseInt", "parseInt()")}}
+
+

Die parseInt() Funktion liest einen String als Argument ein und gibt eine ganze Zahl der Spezifizierten Basis zurück (die Basis ist in der Mathematik das Zahlensystem).

+
+
{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}
+
+

Die decodeURI() Methode decodiert einen Uniform Resource Identifier (URI), der vorher mit der {{jsxref("Global_Objects/encodeURI", "encodeURI")}} Funktion order einer ähnlichen Funktion erstellt wurde.

+
+
{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent()")}}
+
+

Die decodeURIComponent() Methode decodiert eine Uniform Resource Identifier (URI) Komponente, die vorher mit der {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} Funktion oder einer ähnlichen Funktion erstellt wurde.

+
+
{{jsxref("Global_Objects/encodeURI", "encodeURI()")}}
+
+

Die encodeURI() Methode codiert einen Uniform Resource Identifier (URI), indem jedes besondere Zeilen durch eine Sequenz aus zwei drei oder vier Zeichen escaped wird. Dieses Sequenzen Repräsentieren die UTF-8 Darstellung der Zeichen (wird nur vier escape Sequenzen von Zeichen zu zwei zwei Platzhalterzeichen umwandeln)

+
+
{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent()")}}
+
+

Die encodeURIComponent() Methode codiert eine Uniform Resource Identifier (URI) Komponente, indem jedes besondere Zeilen durch eine Sequenz aus zwei drei oder vier Zeichen escaped wird. Dieses Sequenzen Repräsentieren die UTF-8 Darstellung der Zeichen (wird nur vier escape Sequenzen von Zeichen zu zwei zwei Platzhalterzeichen umwandeln)

+
+
{{jsxref("Global_Objects/escape", "escape()")}} {{deprecated_inline}}
+
+

Die veraltete escape() Methode berechnet einen neuen String indem manche Zeichen durch Hexadezimalsequenzen ersetzt werden. Man sollte {{jsxref("Global_Objects/encodeURI", "encodeURI")}} oder {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} stattdessen benutzen.

+
+
{{jsxref("Global_Objects/unescape", "unescape()")}} {{deprecated_inline}}
+
+

Die veraltete unescape() Methode berechnet einen neuen String indem Hexadezimalsequenzen durch die repräsentierenden Zeichen ersetzt werden. Die Hexadezimalsequenzen können von Funktionen wie {{jsxref("Global_Objects/escape", "escape")}} eingeführt werden. Weil unescape() veraltet ist, sollte man stattdessen die Funktion {{jsxref("Global_Objects/decodeURI", "decodeURI()")}} oder {{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} benutzen.

+
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Schleifen_und_Iterationen", "Web/JavaScript/Guide/Ausdruecke_und_Operatoren")}}

diff --git a/files/de/web/javascript/guide/grammatik_und_typen/index.html b/files/de/web/javascript/guide/grammatik_und_typen/index.html new file mode 100644 index 0000000000..3ca2b9936b --- /dev/null +++ b/files/de/web/javascript/guide/grammatik_und_typen/index.html @@ -0,0 +1,699 @@ +--- +title: Grammatik und Typen +slug: Web/JavaScript/Guide/Grammatik_und_Typen +tags: + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Einführung", "Web/JavaScript/Guide/Kontrollfluss_und_Fehlerbehandlung")}}
+ +

Dieses Kapitel behandelt die grundlegende Grammatik von JavaScript, Deklaration von Variablen, Datentypen und Objektinstanzen.

+ +

Grundlagen

+ +

JavaScript leiht sich den größten Teil seiner Syntax von Java, ist aber auch von Sprachen wie Awk, Perl und Python beeinflusst.

+ +

JavaScript ist case-sensitiv (unterscheidet zwischen Groß- und Kleinschreibung) und benutzt den Unicode-Zeichensatz. Zum Beispiel kann das Wort Früh als Variablenname genutzt werden.

+ +
var Früh = "foobar";
+
+ +

Jedoch ist die Variable früh nicht dieselbe wie Früh, weil JavaScript case-sensitiv ist.

+ +

In JavaScript heißen Anweisungen "{{Glossary("Statement", "statements")}}" und werden durch ein Semikolon (;) voneinander getrennt. Ein Semikolon ist nicht nötig, wenn jedes Statement in einer neuen Zeile ist. Wenn mehrere Statements in einer Zeile geschrieben werden, sollte nach jedes mit einem Semikolon trennen. Zudem ist es gängige Praxis, hinter jedem Statement ein Semikolon zu schreiben. Leerzeichen, Tabulatoren und Zeilenumbrüche werden "Whitespace" genannt. Der Quelltext von JavaScript wird vom Interpreter von links nach rechts gelesen und in Sequenzen von Eingabe-Elementen wie JavaScript-Tokens, Steuerzeichen, Zeichenumbrüche, Kommentare und Objektinstanzen (Literale) umgewandelt. ECMAScript beschreibt für den Interpreter reservierte Schlüsselwörter sowie Objektinstanzen und hat eingebaute Regeln für die automatische Einfügung von Semikola (ASI) um Anweisungen zu beenden. Es wird jedoch empfohlen jede Anweisung mit einem Semikolon zu beenden; dies vermeidet ungewollte Nebeneffekte. Mehr Informationen dazu sind in der detaillierten Referenz über JavaScripts lexikalische Grammatik zu finden.

+ +

Kommentare

+ +

Die Syntax von Kommentaren ist dieselbe wie in C++ und in vielen anderen Sprachen:

+ +
// Einzeiliger Kommentar
+
+/* Das ist ein langer,
+ * mehrzeiliger Kommentar
+ */
+
+/* Man kann keine Kommentare, /* Verschachteln */ SyntaxError */
+ +

Kommentare sind wie Whitespaces und werden bei der Ausführung von Skripten verworfen.

+ +

Deklarationen

+ +

Es gibt drei mögliche Arten, Variablen zu deklarieren:

+ +
+
{{jsxref("Statements/var", "var")}}
+
Deklariert eine Variable. Optional wird ein Wert initialisiert.
+
{{jsxref("Statements/let", "let")}}
+
Deklariert eine Variable mit Gültigkeit im aktuellen Block. Optional wird ein Wert initialisiert.
+
{{jsxref("Statements/const", "const")}}
+
Deklariert eine Konstante mit Gültigkeit im aktuellen Block.
+
+ +

Variablen

+ +

Variablen werden benutzt, um Werte zu speichern. Dabei gibt man einer Variablen einen Namen, der {{Glossary("identifier", "Bezeichner")}} bzw. Bezeichner genannt wird und der bestimmten Regeln folgt.

+ +

Ein JavaScript Bezeichner muss mit einem Buchstaben, Unterstrich (_) oder einem Dollarzeichen ($) beginnen. Die nachfolgenden Zeichen können auch Zahlen sein. Da JavaScript case-sensitive ist, wird zwischen Groß- und Kleinschreibung unterschieden und somit repräsentiert "A" einen anderen Buchstaben als "a".

+ +

Es kann ein Großteil der ISO 8859-1 und Unicode-Zeichen benutzt werden, wie z.B. ü oder auch å, aber auch Unicode escape sequences können genutzt werden.

+ +

Beispiele für zulässige Bezeichner sind Number_hits, temp99 und _name.

+ +

Variablendeklaration

+ +

Die Deklaration einer Variable ist durch drei unterschiedliche Wege möglich:

+ + + +

Variablen auswerten

+ +

Eine Variable, die mit var ohne Initialisierung deklariert wurde, hat den Wert {{jsxref("undefined")}}.

+ +

Der Zugriff auf eine nicht initialisierte Variable und der Zugriff auf eine let-Variable, bevor diese Initialisiert wurde, erzeugt einen {{jsxref("ReferenceError")}} Fehler:

+ +
var a;
+console.log("Der Wert von a ist " + a); // Der Wert von a ist undefined
+
+console.log("Der Wert von b ist " + b); // Der Wert von b ist undefined
+var b;
+
+console.log("Der Wert von c ist " + c); // ReferenceError: c is not defined
+
+let x
+console.log("Der Wert von x ist " + x); // Der Wert von x ist undefined
+
+console.log("Der Wert von y ist " + y); // ReferenceError: y is not defined
+let y;
+
+ +

undefined kann benutzt werden, um zu überprüfen ob eine Variable einen Wert hat. Im Folgenden Codebeispiel ist der Variable input kein Wert zugewiesen worden und das if-Statement wird somit true ausgeben.

+ +
var input;
+if(input === undefined){
+  macheDas();
+} else {
+  macheDasAndere();
+}
+
+ +

undefined verhält sich wie ein false, wenn es in einem boolschen Kontext verwendet wird. Zum Beispiel wird im folgendem Codebeispiel die Funktion myFunction ausgeführt, weil das myArray Element undefined ist:

+ +
var myArray = [];
+if (!myArray[0]) myFunction();
+
+ +

undefined wird zu NaN (Not a Number) konvertiert, wenn es in einem numerischen Kontext verwendet wird:

+ +
var a;
+a + 2;  //NaN
+ +

Wenn eine {{jsxref("null")}} Variable ausgewertet wird, verhält sie sich im numerischen Kontext wie 0 und in booleschem Kontext wie false:

+ +
var n = null;
+console.log(n * 32);  // wird 0 in die Konsole eintragen
+
+ +

Variablen Scope

+ +

Wird eine Variable außerhalb eines Code-Blocks deklariert, wird sie eine globale Variable genannt, da sie jetzt in jedem Bereich verfügbar ist. Wenn eine Variable jedoch innerhalb eines Code-Blocks deklariert wird, so ist sie nur innerhalb dieses Blocks verfügbar und wird aus diesem Grund lokale Variable genannt.

+ +

JavaScript hatte vor ECMAScript 2015 keinen Block-Anweisungs Scope; daher wurde eine deklarierte Variable in einem Block immer zu der Funktion (oder dem globalen Scope) gezählt, in dem sich der Block befand. Zum Beispiel wird der folgende Quelltext 5 ausgeben, weil der Scope von x die Funktion ist bzw. der globale Kontext, in dem x deklariert wurde, und nicht der Block, in diesem Fall die if Anweisung, selbst.

+ +
if (true) {
+  var x = 5;
+}
+console.log(x);  // 5
+
+ +

Das Verhalten ändert sich, wenn man die in ECMAScript 2015 eingeführte let Deklaration benutzt.

+ +
if (true) {
+  let y = 5;
+}
+console.log(y);  // ReferenceError: y is not defined
+
+ +

Variablen hochziehen (hoisting)

+ +

Eine andere Besonderheit mit Variablen in JavaScript ist, dass man eine Variable referenzieren kann, bevor sie deklariert wurde, ohne das es zu einem Fehler kommt. Diese Konzept ist bekannt als hoisting (hochziehen); Variablen in JavaScript sind hochgezogen und quasi zum Anfang der Funktion oder des Statements gehoben worden. Immer wenn Variablen hochgezogen werden, werden sie den Wert undefined zurückgeben. So wird immer undefined zurückgegeben, wenn man die Variablen benutzt, bevor sie deklariert und initialisiert wurden.

+ +
/**
+ * Beispiel 1
+ */
+console.log(x === undefined); // true
+var x = 3;
+
+/**
+ * Beispiel 2
+ * wird den Wert undefined zurückgeben
+ */
+var myvar = "my value";
+
+(function() {
+  console.log(myvar); // undefined
+  var myvar = "local value";
+})();
+
+ +

Das obere Beispiel wird genauso interpretiert, wie das folgende Beispiel:

+ +
/**
+ * Beispiel 1
+ */
+var x;
+console.log(x === undefined); // true
+x = 3;
+
+/**
+ * Beispiel 2
+ */
+var myvar = "my value";
+
+(function() {
+  var myvar;
+  console.log(myvar); // undefined
+  myvar = "local value";
+})();
+
+ +

Wegen des Hochziehens sollten alle var Anweisungen so weit am Anfang der Funktion wie nur möglich platziert werden. Dieses Vorgehen verbessert die Qualität des Quelltextes.

+ +

In ECMAScript 2015 wird let (bzw. const) nicht an den Anfang eines Blocks hochgezogen. Das Referenzieren der Variable in dem Block, bevor diese deklariert wurde, führt zu einem {{jsxref("ReferenceError")}}. Die Variable ist in einer "temporären toten Zone", die vom Start des Blocks bis zur Deklaration der Variablen besteht.

+ +
console.log(x); // ReferenceError
+let x = 3;
+ +

Funktionen hochziehen (hoisting)

+ +

Bei Funktionen (nur Funktionsdeklarationen) werden die Deklarationen ebenfalls nach oben gezogen. Bei Funktionsausdrücken gilt das jedoch nicht.

+ +
/* Funktionsdeklaration */
+
+foo(); // "bar"
+
+function foo() {
+   console.log("bar");
+}
+
+
+/* Funktionsausdruck */
+
+baz(); // TypeError: baz ist keine Funktion
+
+var baz = function() {
+   console.log("bar2");
+};
+
+ +

Globale Variablen

+ +

Globale Variablen sind faktisch Eigenschaften des globalen Objekts. In Webseiten ist das globale Objekt das {{domxref("window")}} Objekt, so dass globale Variablen gesetzt und erreicht werden können, indem die Syntax window.variable eingesetzt wird.

+ +

Folglich kann man globale Variablen, die in einem window oder frame deklariert wurden, aus einem anderen window oder Frame erreichen, indem der window oder framename angegeben wird. Zum Beispiel kann eine Variable phoneNumber, die in einem Dokument deklariert wurde, von einem iframe mit parent.phoneNumber erreicht werden.

+ +

Konstanten

+ +

Man kann eine nur lesende, benannte Konstante mit dem Schlüsselwort {{jsxref("Statements/const", "const")}} erstellen. Die Syntax für einen Konstantenbezeichner ist dieselbe, wie für Variablenbezeichner: Er muss mit einem Buchstaben, Unterstrich oder Dollarzeichen beginnen und kann alphabetische Zeichen, numerische Zeichen und Unterstriche enthalten.

+ +
const PI = 3.14;
+
+ +

Der Wert einer Konstanten kann nicht zur Laufzeit durch Zuweisungen oder Neudeklarationen geändert werden. Konstanten müssen deswegen immer initialisiert werden.

+ +

Die Sichtbarkeitsregeln (Scope) bei Konstanten sind die gleichen, wie für let Blockscope Variablen. Wenn das Schüsselwort const weggelassen wird, wird vorausgesetzt, dass der Bezeichner eine Variable repräsentiert.

+ +

Man kann keine Konstante mit dem gleichen Namen einer Funktion oder Variablen im gleiche Gültigkeitsbereich deklarieren. Zum Beispiel:

+ +
// DAS WIRD ZU EINEM ERROR FÜHREN
+function f() {};
+const f = 5;
+
+// DAS WIRD EBENFALLS ZU EINEM ERROR FÜHREN
+function f() {
+  const g = 5;
+  var g;
+
+  //statements
+}
+
+ +

Immer, wenn Objektattribute nicht geschützt sind, werden die folgenden Anweisungen ohne Probleme ausgeführt.

+ +
const MY_OBJECT = {"key": "value"};
+MY_OBJECT.key = "otherValue";
+ +

Jedoch ist der Inhalt eines Arrays nicht geschützt, sodass folgendes Statement ohne Probleme ausgeführt wird.

+ +
const MY_ARRAY = ['HTML','CSS'];
+MY_ARRAY.push('JAVASCRIPT');
+console.log(MY_ARRAY); // logs ['HTML','CSS','JAVASCRIPT']
+
+ +

Datenstrukturen und -typen

+ +

Datentypen

+ +

Der neuste ECMAScript Standard definiert sieben Datentypen:

+ + + +

Obwohl die Anzahl der Datentypen relativ klein ist, eröffnen sie die Möglichkeit nützliche Funktionen für Applikationen zu erstellen. {{jsxref("Object", "Objects")}} und {{jsxref("Function", "functions")}} sind die anderen fundamentalen Elemente der Sprache. Man kann sich Objekte als benannte Container für Werte und Funktionen, die die Applikation ausführen kann, vorstellen.

+ +

Datentypkonvertierungen

+ +

JavaScript ist eine dynamisch typisierte Sprache. Das bedeutet, dass man den Datentypen einer Variable bei der Deklaration nicht mit angibt. Der Datentyp wird während der Ausführung automatisch konvertiert, wenn es notwendig ist. So kann eine Variable folgendermaßen definiert werden:

+ +
var answer = 42;
+
+ +

Und Später kann der gleichen Variablen eine Zeichenkette zugewiesen werden:

+ +
answer = "Thanks for all the fish...";
+
+ +

Weil JavaScript dynamisch typisiert ist, erzeugt diese Zuweisung keinen Fehler im Programm.

+ +

In Ausdrücken, in denen Zahlen und Zeichenketten mit dem + Operator gebraucht werden, konvertiert JavaScript die Zahlen in Zeichenketten. Siehe dazu das folgende Beispiel:

+ +
x = "The answer is " + 42 // "The answer is 42"
+y = 42 + " is the answer" // "42 is the answer"
+
+ +

In Ausdrücken mit anderen Operatoren, konvertiert JavaScript zahlen nicht in Zeichenketten. Zum Beispiel:

+ +
"37" - 7 // 30
+"37" + 7 // "377"
+
+ +

Konvertieren von Zeichenketten zu Zahlen

+ +

In Fällen, in denen eine Zahl durch einen String repräsentiert wird, gibt es folgende Methoden, um die Zeichenkette in eine Zahl umzuwandeln.

+ + + +

parseInt gibt nur ganze Zahlen zurück, weshalb der Einsatz für Dezimalzahlen nicht geeignet ist. Zu einem guten Programmierstil gehört es, dass man immer die Basis bei parseInt mit angibt. Der radix Parameter der Methode gibt an, aus welchem Zahlensystem die Zahl stammt.

+ +

Eine alternative Methode, um einen String in eine Zahl zu konvertieren ist der + (unär Plus) Operator:

+ +
"1.1" + "1.1" // "1.11.1"
+(+"1.1") + (+"1.1") // 2.2
+// Hinweis: die hinzugefügten Klammern sind nur für die Lesbarkeit.
+ +

Literale

+ +

Man benutzt Literale, um in JavaScript Werte zu repräsentieren. Es sind feste Werte, keine Variablen, die man in einem Skript einsetzt. Dieses Kapitel beschreibt die folgeden Literaltypen:

+ + + +

Array Literal

+ +

Ein Array Literal ist eine Liste von null oder mehr Ausdrücken. Jeder Ausdruck repräsentiert ein Element des Arrays. Diese Elemente sind von eckigen Klammern ([]) umschlossen. Wenn ein Array mit einem Array Literal erstellt wird, wird das Array mit allen definierten Elementen initialisiert und die länge des Arrays wird auf die Menge der Elemente gesetzt.

+ +

Das folgende Beispiel erstellt das coffees Array mit drei Elementen und der Länge drei:

+ +
var coffees = ["French Roast", "Colombian", "Kona"];
+
+ +
+

Hinweis: Ein Array Literal ist eine Art von Objektinitialisierung. Sie dazu auch den Einsatz von Objektinitialisierern.

+
+ +

Wenn ein Array durch ein Literal im Toplevel Skript erstellt wird, interpretiert JavaScript das Array immer dann, wenn ein Ausdruck dieses Literal enthält. Im Gegensatz dazu wird ein Literal in einer Funktion immer neu erstellt, wenn die Funktion aufgerufen wird.

+ +

Array Literale sind ebenfalls Array Objekte. Für mehr Details siehe {{jsxref("Array")}} und Indexed collections.

+ +

Extra Kommas in Array Literalen

+ +

Man muss nicht alle Elemente in einem Array Literal spezifizieren. Wenn man zwei Kommas in einer Reihe verwendet, wird das Array mit einem undefined Element erstellt. Das folgende Beispiel erstellt das fish Array:

+ +
var fish = ["Lion", , "Angel"];
+
+ +

Dieses Array hat zwei Elemente mit Werten und ein leeres Element (fish[0] ist "Lion", fish[1] ist undefined und fish[2] ist "Angel").

+ +

Wenn man ein trennendes Komma am Ende der Elementliste hinzufügt, wird es ignoriert. Im folgenden Beispiel ist die Länge des Arrays drei. Es gibt kein myList[3]. Alle weiteren Kommas in der Liste führen zu einem neuen Element.

+ +
+

Hinweis: Trennende Kommas können in älteren Browserversionen zu Fehlern führen. Zudem ist es ein guter Stil diese Kommas zu entfernen.

+
+ +
var myList = ['home', , 'school', ];
+
+ +

Im folgenden Beispiel hat das Array vier Elemente und myList[0] und myList[2] sind nicht spezifiziert.

+ +
var myList = [ , 'home', , 'school'];
+
+ +

Im folgenden Beispiel hat das Array vier Elemente und myList[1] und myList[3] sind nicht spezifiziert. Nur das letzte Komma wird ignoriert.

+ +
var myList = ['home', , 'school', , ];
+
+ +

Das Verständnis für das Verhalten von extra Kommas ist wichtig, um JavaScript als Sprache zu verstehen. Immer, wenn man seinen eigenen Quelltext schreibt, sollten explizit fehlenden Elementen mit undefined deklariert werden, damit die Lesbarkeit und Wartbarkeit des Quelltextes besser ist.

+ +

Boolean Literale

+ +

Der Boolean Typ hat zwei Literale: true und false.

+ +

Man sollte die primitiven Werte true und false jedoch nicht mit den Werten true und false des Boolean Objektes verwechseln. Das Boolean Objekt ist eine Hülle um den primitiven Boolean Datentypen. Siehe im Artikel {{jsxref("Boolean")}} für weitere Informationen.

+ +

Numerische Literale

+ +

Ganze Zahlen können als Dezimal- (Basis 10), Hexadezimal- (Basis 16), Oktal- (Basis 8) und Binärzahl (Basis 2) ausgedrückt werden.

+ + + +

Im folgenden Beispiel sind einige Beispiele für Zahlenliterale:

+ +
0, 117 und -345 (dezimal, Basis 10)
+015, 0001 und -0o77 (oktal, Basis 8)
+0x1123, 0x00111 und -0xF1A7 (hexadezimal, "hex", Base 16)
+0b11, 0b0011 und -0b11 (binär, Basis 2)
+
+ +

Für weitere Informationen siehe numerische Literale in der Lexikalischen Grammatik Referenz.

+ +

Gleitkomma Literale

+ +

Ein Gleitkomma Literal kann die folgenden Abschnitte beinhalten:

+ + + +

Der Exponent besteht aus einem "e" oder "E" gefolgt von einer ganzen Zahl, die mit einem Vorzeichen ("+" oder "-") versehen sein kann. Eine Gleitkommazahl muss mindestens aus einer Ziffer und entweder einem Dezimalpunkt oder einem "e" (oder "E") bestehen.

+ +

Kurz und knapp sieht die Syntax folgendermaßen aus:

+ +
[(+|-)][ziffern][.ziffern][(E|e)[(+|-)]ziffern]
+
+ +

Zum Beispiel:

+ +
3.1415926
+-.123456789
+-3.1E+12
+.1e-23
+
+ +

Objekt Literale

+ +

Ein Objekt Literal ist eine Liste von null oder mehr Paaren von Eigenschaftsnamen und -werten, umschlossen von geschweiften Klammern ({}). Man sollte kein Objektliteral am Anfang eines Statements benutzen. Das wird zu einem Fehler führen oder nicht wie erwartet funktionieren, weil das {-Zeichen als Anfang eines Blocks interpretiert wird.

+ +

Es folgt ein Beispiel für ein Objekt Literal. Das erste Element des car Objektes definiert eine Eigenschaft myCar und beschreibt diese mit einem neuen String "Saturn". Am zweiten Element, der getCar Eigenschaft, wird der Rückgabewert der aufgerufenen Funktion carTypes("Honda") zugewiesen. Das dritte Element, die special Eigenschaft, benutzt eine existierende Variable sales.

+ +
var sales = "Toyota";
+
+function carTypes(name) {
+  if (name === "Honda") {
+    return name;
+  } else {
+    return "Sorry, we don't sell " + name + ".";
+  }
+}
+
+var car = {
+  myCar: "Saturn",
+  getCar: carTypes("Honda"),
+  special: sales
+};
+
+console.log(car.myCar);   // Saturn
+console.log(car.getCar);  // Honda
+console.log(car.special); // Toyota
+
+ +

Für die Namen der Eigenschaften kann auch ein String oder ein Zahlen Literal verwendet werden. Für den Wert kann auch ein verschachteltes Objekt Literal genutzt werden. Das folgende Beispiel nutzt diese Optionen.

+ +
var car = { manyCars: {a: 'Saab', b: 'Jeep'}, 7: 'Mazda' };
+
+console.log(car.manyCars.b); // Jeep
+console.log(car[7]); // Mazda
+
+ +

Die Namen von Objekteigenschaften können ein String sein, was auch den leeren String beinhaltet. Wenn die Eigenschaftsnamen keine gültigen JavaScript {{Glossary("Identifier","Bezeichner")}} sind, müssen sie in Anführungszeichen geschrieben werden. Eigenschaftsnamen die keine gültigen Bezeichner sind, können nicht mit der Punktschreibweise (.) erreicht werden. Wohl aber mit der Array ähnlichen Notation ("[]").

+ +
var unusualPropertyNames = {
+  "": "An empty string",
+  "!": "Bang!"
+}
+console.log(unusualPropertyNames."");   // SyntaxError: Unexpected string
+console.log(unusualPropertyNames[""]);  // An empty string
+console.log(unusualPropertyNames.!);    // SyntaxError: Unexpected token !
+console.log(unusualPropertyNames["!"]); // Bang!
+ +

Erweiterte Objekt Literale

+ +

In ES2015 wurde das Objekt Literal dahingehend erweitert, dass der Prototyp bei der Erstellung gesetzt wird. Desweiteren sind neue Funktionalitäten hinzugekommen, die eine Kurzschreibweise für foo: foo Zuweisungen, die Definitionen für Methoden, das Aufrufen von super Methoden und die Berechnung der Eigenschaftsnamen mit Ausdrücken ermöglichen. Alle diese Funktionen bringen zum Einen Klassendefinition und Objekt Literale näher zusammen und sind somit objektbasiertes Design und zum Anderen häufig vorteilhafter und bequemer.

+ +
var obj = {
+    // __proto__
+    __proto__: theProtoObj,
+    // Shorthand for ‘handler: handler’
+    handler,
+    // Methods
+    toString() {
+     // Super calls
+     return "d " + super.toString();
+    },
+    // Computed (dynamic) property names
+    [ 'prop_' + (() => 42)() ]: 42
+};
+ +

Bitte beachten:

+ +
var foo = {a: "alpha", 2: "two"};
+console.log(foo.a);    // alpha
+console.log(foo[2]);   // two
+//console.log(foo.2);  // Error: missing ) after argument list
+//console.log(foo[a]); // Error: a is not defined
+console.log(foo["a"]); // alpha
+console.log(foo["2"]); // two
+
+ +

RegExp Literale

+ +

Ein RegExp Literal (welcher im Detail später erklärt wird) ist ein Pattern (Muster) umschlossen von Slashes (/). Das Folgende ist ein Beispiel für ein RegExp Literal:

+ +
var re = /ab+c/;
+ +

String Literale

+ +

Ein String Literal besteht aus null oder mehr Zeichen, die von doppelten (") oder einfachen (') Anführungszeichen umschlossen sind. Ein String muss immer von gleichen Anführungszeichen umschlossen sein. Entweder von einfachen oder von doppelten Anführungszeichen. Im folgenden Beispiel sind ein paar String Literale gezeigt:

+ +
"foo"
+'bar'
+"1234"
+"eine Zeile \n weitere Zeile"
+"John's cat"
+
+ +

Man kann alle Methoden des String Objektes auf einem String Literal aufrufen, denn JavaScript konvertiert das Literal automatisch in ein temporäres String Objekt, führt die Methode aus und verwirft danach das temporäre Objekt. Man kann auch die String.length Eigenschaft mit einem String Literal benutzen:

+ +
console.log("John's cat".length)
+// Wird die Anzahl der Zeichen (auch Leerzeichen) ausgeben.
+// In diesem Fall 10.
+
+ +

In ES2015, wurden zudem Template Literale eingeführt. Template Literale sind von Backticks (` `) (Gravis) umschlossen. Template Strings bieten syntaktischen Zucker für das Erstellen von Strings an. Sie sind vergleichbar mit den String Interpolations Funktionen in Perl, Python und anderen Sprachen. Optional können Marken eingefügt werden, um einen String benutzerdefiniert zu erstellen. Sie vermeiden Injection-Attacken und ermöglichen es Datenstrukturen in Strings unterzubringen.

+ +
// Standardliteral für die String erstellung
+`In JavaScript '\n' is a line-feed.`
+
+// Mehrzellige Strings
+`In JavaScript ist das
+ nicht erlaubt.`
+
+// String Interpolation
+var name = "Bob", time = "today";
+`Hello ${name}, how are you ${time}?`
+
+// Erstellung einer HTTP Anfrage.
+POST`http://foo.org/bar?a=${a}&b=${b}
+     Content-Type: application/json
+     X-Credentials: ${credentials}
+     { "foo": ${foo},
+       "bar": ${bar}}`(myOnReadyStateChangeHandler);
+ +

Man sollte String Literale benutzen, sofern man nicht explizit ein Objekt benötigt. Für weitere Informationen siehe im {{jsxref("String")}} Artikel nach.

+ +

Einsatz von Sonderzeichen in Strings

+ +

Neben den normalen Zeichen ist es auch möglich Sonderzeichen in einem String zu verwenden. Ein Beispiel ist im folgenden zu sehen:

+ +
"eine Zeile \n nächste Zeile"
+
+ +

Die folgende Tabelle Zeigt die Sonderzeichen, die in JavaScript Strings verwendet werden können:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table: JavaScript Sonderzeichen
ZeichenBedeutung
\0Null Byte
\bBackspace
\fForm feed
\nNew line
\rCarriage return
\tTab
\vVertical tab
\'Einfache Anführungszeichen
\"Doppelte Anführungszeichen
\\Backslash Zeichen
\XXXDas Zeichen, das im Latin-1 Encoding mit drei Oktalzahlen (XXX) Spezifiziert wird (0 bis 377). Zum Beispiel ist \251 die Oktalsequenz für das Copyrightsymbol.
\xXXZeichen, die im Latin-1 Encoding mit zwei Hexadezimalzahlen (XX) spezifiziert werden (00 bis FF). Zum Beispiel ist \xA9 die Hexadezimalsequenz für das Copyrightsymbol.
\uXXXXDie Unicode Zeichen, die mit vier Hexadezimalziffern XXXX beschreiben werden. Zum Beispiel ist \u00A9 die Hexadezimalsequenz für das Copyrightsymbol. Siehe Unicode escape Sequenzen.
\u{XXXXX}Unicode code point escapes. Zum Beispiel ist \u{2F804} das gleiche wie das einfache Unicodezeichen \uD87E\uDC04.
+ +

Escaping Zeichen

+ +

Für nicht in der Tabelle gezeigte Zeichen wird ein voranstehendes Backslash ignoriert. Der Einsatz von Backslashs ist Veraltet und sollte vermieden werden.

+ +

Man kann Anführungszeichen in einen String hinzufügen, indem ein Führendes Backslash eingesetzt wird. Das wird auch escaping der Anführungszeichen genannt. Ein Beispiel:

+ +
var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
+console.log(quote);
+
+ +

Das Ergebnis ist:

+ +
He read "The Cremation of Sam McGee" by R.W. Service.
+
+ +

Um ein Backslash in einem String zu verwenden, muss dieses mit einem Backslash escaped werden. Zum Beispiel muss der Pfad c:\temp wie folgt geschrieben werden:

+ +
var home = "c:\\temp";
+
+ +

Man kann zudem Zeilenumbrüche mit einem vorangegangenen Backslash escapen. Das Backslash und der Zeilenumbruch werden aus dem String entfernt.

+ +
var str = "this string \
+is broken \
+across multiple\
+lines."
+console.log(str);   // this string is broken across multiple lines.
+
+ +

JavaScript kennt keine "heredoc" Syntax. Um eine solche zu simulieren muss am Ende jeder Zeile mit einem Zeilenumbruch (\n) ein Backslash stehen:

+ +
var poem =
+"Roses are red,\n\
+Violets are blue.\n\
+Sugar is sweet,\n\
+and so is foo."
+
+ +

ECMAScript 2015 führte einen neuen Literaltyp, das Template Literal, ein. Dieses führte, für viele neue Funktionen, Strings mit mehrere Zeilen ein!

+ +
var poem =
+`Roses are red,
+Violets are blue.
+Sugar is sweet,
+and so is foo.`
+
+ +

Mehr Informationen

+ +

Dieses Kapitel beschränkt sich auf die Basissyntax für Deklarationen und Typen. Um mehr über die Sprachkonstrukte von JavaScript zu lernen siehe in die folgenden Kapitel dieses Guides:

+ + + +

Im nächsten Kapitel wird ein Blick auf Kontrollflüsse und Fehlerbehandlungen geworfen.

+ +

{{PreviousNext("Web/JavaScript/Guide/Einführung", "Web/JavaScript/Guide/Kontrollfluss_und_Fehlerbehandlung")}}

diff --git a/files/de/web/javascript/guide/index.html b/files/de/web/javascript/guide/index.html new file mode 100644 index 0000000000..8e9fcfa13b --- /dev/null +++ b/files/de/web/javascript/guide/index.html @@ -0,0 +1,130 @@ +--- +title: Guide +slug: Web/JavaScript/Guide +tags: + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide +--- +

{{jsSidebar("JavaScript Guide")}}

+ +

Der JavaScript Guide stellt einen Überblick zu JavaScript bereit und zeigt wie man die Sprache verwenden kann. Für detaillierte Informationen über einzelne Sprachteile JavaScripts gibt es die JavaScript Referenz.

+ +

Kapitel

+ +

Dieser Guide ist in mehrere Kapitel aufgeteilt:

+ + + + + + + + + +

{{Next("Web/JavaScript/Guide/Introduction")}}

diff --git a/files/de/web/javascript/guide/indexed_collections/index.html b/files/de/web/javascript/guide/indexed_collections/index.html new file mode 100644 index 0000000000..fa47c0841b --- /dev/null +++ b/files/de/web/javascript/guide/indexed_collections/index.html @@ -0,0 +1,448 @@ +--- +title: Indexed collections +slug: Web/JavaScript/Guide/Indexed_collections +tags: + - Guide + - Handbuch + - JavaScript + - Method + - Méthode + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Indexed_collections +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}
+ +

Dieses Kapitel beschreibt Datensammlungen, die nach einem Indexwert sortiert sind. Diese beinhalten Arrays und Array-ähnliche Konstrukte, wie {{jsxref("Array")}} Objekte {{jsxref("TypedArray")}} Objekte.

+ +

Array Objekt

+ +

Ein Array ist ein sortiertes Set an Werten, die mit einem Namen und einem Index referenziert werden. Zum Beispiel könnte ein Array mit dem Namen emp Mitarbeiternamen enthalten, die über ihre Mitarbeiternummer indexiert sind. emp[1] würde somit Mitarbeiter Eins sein, emp[2] ist Mitarbeiter Zwei, und so weiter.

+ +

JavaScript hat keinen expliziten Array-Datentyp, aber es ist möglich, das vordefinierte Array Objekt und dessen Methoden zu verwenden, um mit Arrays zu arbeiten. Das Array Objekt verfügt über Methoden, um Arrays auf unterschiedliche Weisen zu manipulieren. Es hat ein Property um die Arraylänge zu bestimmen, und andere Properties für die Verwendung von Regular Expressions.

+ +

Ein Array erstellen

+ +

Die folgenden Statements erstellen äquivalente Arrays:

+ +
var arr = new Array(element0, element1, ..., elementN);
+var arr = Array(element0, element1, ..., elementN);
+var arr = [element0, element1, ..., elementN];
+
+ +

element0, element1, ..., elementN ist eine Liste von Werten für die Elemente im Array. Das Array wird mit den Werten als Elemente initialisiert. Das length Property des Arrays entspricht dann der Anzahl Argumente.

+ +

Die Bracket-Syntax wird als "Array-Literal" oder "Array-Initialisierer" bezeichnet. Es ist eine kürzere Form der Array-Erstellung und wird allgemein bevorzugt. Siehe Array literals für weitere Details.

+ +

Um ein leeres Array mit einer Länge von mehr als Null zu erstellen, kann eine der folgenden Statements verwendet werden:

+ +
var arr = new Array(arrayLength);
+var arr = Array(arrayLength);
+
+// Folgendes hat den selben Effekt.
+var arr = [];
+arr.length = arrayLength;
+
+ +
+

Bemerkung : im obigen Code, arrayLength muss ein Number Objekt sein, ansonsten wird ein Array mit einem Element (dem übergebenen Wert) erstellt. Ein Aufruf von arr.length wird arrayLength zurückgeben, aber das Array besteht aus leeren (undefined) Elementen. Eine {{jsxref("Statements/for...in","for...in")}} Schleife wird keine der Elemente aus dem Array zurückgeben.

+
+ +

Neben der Zuweisung an eine neue Variable, wie im Beispiel oben gezeigt, können Arrays auch als Property eines neuen oder existierenden Objekts zugewiesen werden:

+ +
var obj = {};
+// Weist das Array einem Property des bestehenden Objekts 'obj'
+// zu.
+obj.prop = [element0, element1, ..., elementN];
+
+// Weist das Array einem Property auf dem neuen Objekt 'obj'
+// zu.
+var obj = {prop: [element0, element1, ...., elementN]};
+
+ +

Wenn ein Array mit einem einzelnen Number Objekt erstellt werden soll, muss die Bracket-Syntax verwendet werden. Wenn ein einzelnes Number Objekt an den/der Array() Konstruktor oder Funktion übergeben wird, wird es als arrayLength und nicht als einzelnes Element interpretiert.

+ +
var arr = [42];      // Erstellt ein Array mit genau einem
+                     // Element: der Nummer 42.
+
+var arr = Array(42); // Erstellt ein Array ohne Elemente und
+                     // arr.length wird als 42 gesetzt; dies
+                     // ist äquivalent zu:
+var arr = [];
+arr.length = 42;
+
+ +

Wenn Array(N) aufgerufen wird und N keine Ganzzahl ist, wird ein RangeError geworfen. Das folgende Beispiel illustriert dieses Verhalten:

+ +
var arr = Array(9.3);  // RangeError: Invalid array length
+                       // "Ungültige Array-Länge"
+ +

Wenn im Code Arrays mit einzelnen Elements eines willkürlichen Datentyp verlangt sind, ist es sicherer, Array-Literals zu verwenden, oder zuerst ein leeres Array zu erstellen und dann das einzelne Element hinzuzufügen.

+ +

Ein Array abfüllen

+ +

Ein Array kann abgefüllt werden, indem dessen Elemente mit Werten abgefüllt werden:

+ +
var emp = [];
+emp[0] = 'Casey Jones';
+emp[1] = 'Phil Lesh';
+emp[2] = 'August West';
+
+ +
+

Bemerkung : Wenn ein Wert dem Array-Operator übergeben wird, der kein Integer ist, wie im obigen Code, wird ein Property auf dem Array-Objekt erstellt, statt als Array-Element.

+ +

Der Array-Operator ist die Rechteckige Klammer nach der Array-Variable.

+
+ +
var arr = [];
+arr[3.4] = 'Oranges';
+console.log(arr.length);                // 0
+console.log(arr.hasOwnProperty(3.4));   // true
+
+ +

Arrays können auch bei der Erstellung abgefüllt werden:

+ +
var myArray = new Array('Hello', myVar, 3.14159);
+var myArray = ['Mango', 'Apple', 'Orange'];
+
+ +

Array-Elemente referenzieren

+ +

Ein Element in einem Array kann mit dessen Ordinalzahl (Index) referenziert werden. Beispielweise wird der folgende Array erstellt:

+ +
var myArray = ['Earth', 'Wind', 'Fire'];
+
+ +

Das erste Element kann mit myArray[0], und das zweite Element des Arrays mit myArray[1] referenziert werden. Der Index der Elemente beginnt mit Null.

+ +
+

Bemerkung : Der Array-Operator (Rechteckige Klammer) wird auch für den Zugriff auf die Properties des Arrays (Arrays sind in JavaScript auch Objekte) verwendet. Beispielsweise:

+
+ +
var arr = ['one', 'two', 'three'];
+arr[2];                            // three
+arr['length'];                     // 3
+
+ +

Das length Property verstehen

+ +

Auf dem Implementierungslevel, Arrays in JavaScript legen ihre Elemente als normale Properties eines Objekts (dem Array selbst) mit dessen Index als Property-Name ab. Das length Property ist speziell; Es gibt immer den Index des letzen Elements plus Eins (im folgenden Beispiel hat Dusty den Index 30, also gibt cats.length 30 + 1 zurück) zurück. Array-Indexe starten in JavaScript immer mit 0 und nicht mit 1. Dies bedeutet, dass das length Property immer um Eins grösser ist, als der höchste Index im Array:

+ +
var cats = [];
+cats[30] = ['Dusty'];
+console.log(cats.length); // 31
+
+ +

Das length Property kann auch beschrieben werden. Wird ein Wert zugewiesen, der kleiner ist, als die Anzahl Elemente im Array, wird das Array auf die angegebene Grösse geschrumpft; das Array wird geleert, wenn 0 zugewiesen wird:

+ +
var cats = ['Dusty', 'Misty', 'Twiggy'];
+console.log(cats.length); // 3
+
+cats.length = 2;
+console.log(cats); // Loggt "Dusty, Misty" - Twiggy wurde
+                   // entfernt.
+
+cats.length = 0;
+console.log(cats); // Loggt nichts; Das 'cats' Array ist leer.
+
+cats.length = 3;
+console.log(cats); // Loggt [undefined, undefined, undefined].
+
+ +

Iteration über Arrays

+ +

Eine gebräuchliche Operation ist die Iteration über die Werte eines Arrays, um jedes Element auf eine Weise zu verarbeiten. Die einfachste Variate ist:

+ +
var colors = ['red', 'green', 'blue'];
+for (var i = 0; i < colors.length; i++) {
+  console.log(colors[i]);
+}
+
+ +

Wenn es ausgeschlossen ist, dass eines der Elemente im Array in einem Boolean-Kontext als false evaluiert wird — beispielsweise, wenn es nur aus DOM Knoten besteht — kann ein effizienterer Ausdruck verwendet werden:

+ +
var divs = document.getElementsByTagName('div');
+for (var i = 0, div; div = divs[i]; i++) {
+  /* Verarbeite das div auf irgendeine Weise. */
+}
+
+ +

Dies vermeidet den Overhead bei der Überprüfung der Array-Länge und  weist der div Variable den aktuellen Wert des Schleifendurchlaufs sofort zu.

+ +

Die {{jsxref("Array.forEach", "forEach()")}} Methode erlaubt eine andere Variate zur Iteration über ein Array:

+ +
var colors = ['red', 'green', 'blue'];
+colors.forEach(function(color) {
+  console.log(color);
+});
+
+ +

Die Funktion, die forEach übergeben wird, wird für jedes Element im Array ausgeführt, wobei das Element als Argument der Funktion übergeben wird. Elemente ohne Wert (undefined) werden von forEach nicht iteriert.

+ +

Elemente ohne Wert werden von forEach nur übersprungen, wenn sie nicht manuell zugewiesen wurden:

+ +
var array = ['first', 'second', , 'fourth'];
+
+// Gibt ['first', 'second', 'fourth'] zurück.
+array.forEach(function(element) {
+  console.log(element);
+})
+
+if (array[2] === undefined) { // true
+  console.log('array[2] is undefined');
+}
+
+var array = ['first', 'second', undefined, 'fourth'];
+
+// Gibt ['first', 'second', undefined, 'fourth'] zurück.
+array.forEach(function(element) {
+  console.log(element);
+})
+ +

Weil JavaScript Elemente als normale Objekt-Properties abgelegt werden, ist es nicht ratsam Arrays mit {{jsxref("Statements/for...in","for...in")}} zu iterieren, weil normale Elemente plus alle aufzählbaren (enumerable) Properties aufgelistet werden.

+ +

Array-Methoden

+ +

Das {{jsxref("Array")}} Objekt verfügt über folgende Methoden:

+ +

{{jsxref("Array.concat", "concat()")}} hängt zwei Arrays aneinander und gibt das kombinierte Array zurück.

+ +
var myArray = new Array('1', '2', '3');
+myArray = myArray.concat('a', 'b', 'c');
+// myArray ist nun ["1", "2", "3", "a", "b", "c"].
+
+ +

{{jsxref("Array.join", "join(deliminator = ',')")}} kombiniert alle Elemente eines Arrays in einen String mit einem Delimiter.

+ +
var myArray = new Array('Earth', 'Wind', 'Fire');
+var list = myArray.join(' - '); // list ist
+                                // "Earth - Wind - Fire".
+
+ +

{{jsxref("Array.push", "push()")}} fügt eines oder mehrere Elemente an ein Array und gibt den Wert des neuen length Property zurück.

+ +
var myArray = new Array('1', '2');
+myArray.push('3'); // myArray ist nun ["1", "2", "3"].
+
+ +

{{jsxref("Array.pop", "pop()")}} entfernt das letzte Element des Arrays und gibt es zurück.

+ +
var myArray = new Array('1', '2', '3');
+var last = myArray.pop();
+// myArray ist nun ["1", "2"], last = "3"
+
+ +

{{jsxref("Array.shift", "shift()")}} entfernt das erste Element des Arrays und gibt es zurück.

+ +
var myArray = new Array('1', '2', '3');
+var first = myArray.shift();
+// myArray ist nun ["2", "3"], first = "1"
+
+ +

{{jsxref("Array.unshift", "unshift()")}} fügt eines oder mehrere Elemente an den Anfang des Arrays und gibt den Wert des neuen length Property zurück.

+ +
var myArray = new Array('1', '2', '3');
+myArray.unshift('4', '5');
+// myArray wird ["4", "5", "1", "2", "3"].
+ +

{{jsxref("Array.slice", "slice(start_index, upto_index)")}} extrahiert einen Ausschnitt des Arrays und gibt ein neues Array zurück.

+ +
var myArray = new Array('a', 'b', 'c', 'd', 'e');
+myArray = myArray.slice(1, 4); // Beginnt bei Index 1 und
+                               // extrahiert alle Elemente bis
+                               // Index 3 und gibt somit
+                               // [ "b", "c", "d"] zurück.
+
+ +

{{jsxref("Array.splice", "splice(index, count_to_remove, addElement1, addElement2, ...)")}} entfernt einen Teil des Arrays und ersetzt sie (optional). Der rückgegebene Wert entspricht den entfernten Elementen.

+ +
var myArray = new Array('1', '2', '3', '4', '5');
+myArray.splice(1, 3, 'a', 'b', 'c', 'd');
+// myArray ist nun ["1", "a", "b", "c", "d", "5"].
+// Dieser Code startet mit Index 1 (wo '2' war), entfernt dort
+// 3 Elemente, und fügt die Werte 'a' bis '5' ein.
+
+ +

{{jsxref("Array.reverse", "reverse()")}} kehrt die Reihenfolge der Array-Elemente um; das erste Element ist neu das letzte und das letzte Element ist nun das erste.

+ +
var myArray = new Array('1', '2', '3');
+myArray.reverse();
+// Kehrt die Reihenfolge der Array-Elemente um.
+// myArray = ["3", "2", "1"]
+
+ +

{{jsxref("Array.sort", "sort()")}} sortiert die Elemente im Array.

+ +
var myArray = new Array('Earth', 'Wind', 'Fire');
+myArray.sort();
+// Sortiert das Array.
+// myArray = ["Earth", "Fire", "Wind"]
+
+ +

sort() kann auch eine Callback-Funktion verwenden, um zu bestimmen, wie die Elemente miteinander verglichen werden sollen. Die Funktion vergleicht zwei Werte und gibt einen von drei Werten zurück:

+ +

Beispielsweise wird der folgende Code das Array nach dem letzten Buchstaben des Strings sortieren:

+ +
var sortFn = function(a, b) {
+  if (a[a.length - 1] < b[b.length - 1]) return -1;
+  if (a[a.length - 1] > b[b.length - 1]) return 1;
+  if (a[a.length - 1] == b[b.length - 1]) return 0;
+}
+myArray.sort(sortFn);
+// Sortiert das Array nach dem letzten Buchstaben.
+// myArray = ["Wind","Fire","Earth"]
+ + + +

{{jsxref("Array.indexOf", "indexOf(searchElement[, fromIndex])")}} durchsucht das Array nach searchElement und gibt den Index des ersten Treffers zurück.

+ +
var a = ['a', 'b', 'a', 'b', 'a'];
+console.log(a.indexOf('b')); // Loggt 1.
+// Nochmals, die Suche beginnt ab dem Element mit dem Index 2.
+console.log(a.indexOf('b', 2)); // Loggt 3.
+console.log(a.indexOf('z')); // Loggt -1, weil 'z' nicht
+                             // gefunden wurde.
+
+ +

{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement[, fromIndex])")}} funktioniert wie indexOf, aber startet die Suche am Ende des Arrays.

+ +
var a = ['a', 'b', 'c', 'd', 'a', 'b'];
+console.log(a.lastIndexOf('b')); // Loggt 5.
+// Startet die Suche ab dem Element mit dem Index 4.
+console.log(a.lastIndexOf('b', 4)); // Loggt 1.
+console.log(a.lastIndexOf('z')); // Loggt -1.
+
+ +

{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} führt callback für jedes Element aus.

+ +
var a = ['a', 'b', 'c'];
+a.forEach(function(element) { console.log(element); });
+// Loggt jedes Element.
+
+ +

{{jsxref("Array.map", "map(callback[, thisObject])")}} gibt ein neues Array zurück, aus dem Rückgabewert der callback Funktion.

+ +
var a1 = ['a', 'b', 'c'];
+var a2 = a1.map(function(item) { return item.toUpperCase(); });
+console.log(a2); // Loggt ['A', 'B', 'C'].
+
+ +

{{jsxref("Array.filter", "filter(callback[, thisObject])")}} gibt ein Array zurück, das aus allen Elementen besteht, bei denen die callback Funtion true zurückgibt.

+ +
var a1 = ['a', 10, 'b', 20, 'c', 30];
+var a2 = a1.filter(function(item) { return typeof item === 'number'; });
+console.log(a2); // Loggt [10, 20, 30].
+
+ +

{{jsxref("Array.every", "every(callback[, thisObject])")}} gibt true zurück, wenn die callback Funktion für jedes Element auch true zurückgibt.

+ +
function isNumber(value) {
+  return typeof value === 'number';
+}
+var a1 = [1, 2, 3];
+console.log(a1.every(isNumber)); // Loggt true.
+var a2 = [1, '2', 3];
+console.log(a2.every(isNumber)); // Loggt false.
+
+ +

{{jsxref("Array.some", "some(callback[, thisObject])")}} gibt true zurück, wenn die callback Funktion für alle Elemente mindestens einmal true zurückgibt.

+ +
function isNumber(value) {
+  return typeof value === 'number';
+}
+var a1 = [1, 2, 3];
+console.log(a1.some(isNumber)); // Loggt true.
+var a2 = [1, '2', 3];
+console.log(a2.some(isNumber)); // Loggt true.
+var a3 = ['1', '2', '3'];
+console.log(a3.some(isNumber)); // Loggt false.
+
+ +

Die obige Methoden, die eine callback Funktion als Argument verlangen sind als Iterative Methoden bekannt, weil sie über das ganze Array auf irgendeine Weise iterieren. Jede der Methoden nimmt ein optionales zweites Argument thisObject. Wenn thisObject übergeben wird, wird es im Kontext der callback Funktion als this behandelt. Falls es nicht übergeben wird, wie es auch der Fall ist, wenn eine Funktion ausserhalb eines expliziten Objektkontext aufgerufen wird, referenziert this das globale Objekt ({{domxref("window")}}).

+ +

Die callback Funktion wird jeweils mit drei Argumenten aufgerufen. Das erste ist der Wert des aktuellen Elements in der Iteration, das zweite ist der Index des Elements und das dritte ist eine Referenz auf das Array selbst. JavaScript Funktionen ignorieren Parameter, die in der Liste nicht benannt werden, es ist somit sicher, eine Funktion als callback zu definieren, die nur ein einzelnes Argument nimmt, zum Beispiel alert.

+ +

 

+ +

{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}} wendet callback(firstValue, secondValue) an, um die Liste auf einen einzelnen Wert zu reduzieren.

+ +
var a = [10, 20, 30];
+var total = a.reduce(function(first, second) { return first + second; }, 0);
+console.log(total) // Loggt 60.
+
+ +

{{jsxref("Array.reduceRight", "reduceRight(callback[, initialValue])")}} funktioniert wie reduce(), aber startet am Ende des Arrays.

+ +

reduce und reduceRight sind die unauffälligsten iterativen Array-Methoden. Sie sollten dazu verwendet werden, rekursiv jeweils zwei Werte miteinander zu kombinieren, bis nur noch ein einzelner Wert verbleibt.

+ +

Mehrdimensionale Arrays

+ +

Arrays können verschachtelt sein. Das bedeutet, dass ein Array ein anderes Array als Element beinhalten kann. Mit dieser EIgenschaft von JavaScript können mehrdimensionale Arrays erstellt werden. Der folgende Code erstellt ein zwei-dimensionales Array:

+ +
var a = new Array(4);
+for (i = 0; i < 4; i++) {
+  a[i] = new Array(4);
+  for (j = 0; j < 4; j++) {
+    a[i][j] = '[' + i + ', ' + j + ']';
+  }
+}
+
+ +

Dieses Beispiel erstellt ein Array mit den folgenden Zeilen:

+ +
Zeile 0: [0, 0] [0, 1] [0, 2] [0, 3]
+Zeile 1: [1, 0] [1, 1] [1, 2] [1, 3]
+Zeile 2: [2, 0] [2, 1] [2, 2] [2, 3]
+Zeile 3: [3, 0] [3, 1] [3, 2] [3, 3]
+
+ +

Arrays und Regular Expressions

+ +

Wenn ein Array das Resultat einer Regular Expression auf einem String ist, wird das Array Properties und Elemente zuückgeben, die Informationen zum Match liefern. Der Rückgabewert der {{jsxref("Global_Objects/RegExp/exec","RegExp.exec()")}}, {{jsxref("Global_Objects/String/match","String.match()")}}, und {{jsxref("Global_Objects/String/split","String.split()")}} Methode ist ein Array. Für weitere Informationen für die Verwendung von Arrays mit Regular Expressions, siehe Regular Expressions.

+ +

Mit Array-ähnlichen Objekten arbeiten

+ +

Manche JavaScript Objekte, wie {{domxref("NodeList")}}, welche von {{domxref("document.getElementsByTagName()")}} zurückgegeben oder als {{jsxref("Functions/arguments","arguments")}} in einem Funktionskörper referenziert wird, verhalten sich wie Arrays, aber teilen nicht alle deren Methoden. Das arguments Objekt stellt ein {{jsxref("Global_Objects/Function/length","length")}} Attribut zur Verfügung, implementiert aber beispielsweise nicht die {{jsxref("Array.forEach", "forEach()")}} Methode.

+ +

Array Prototyp-Methoden können auf einem Array-ähnlichen Objekt aufgerufen werden, siehe folgendes Beispiel:

+ +
function printArguments() {
+  Array.prototype.forEach.call(arguments, function(item) {
+    console.log(item);
+  });
+}
+
+ +

Array Prototyp-Methoden können auch für Strings verwendet werden, weil diese einen sequenziellen Zugriff auf deren Zeichen erlauben, ähnlich wie Arrays:

+ +
Array.prototype.forEach.call('a string', function(chr) {
+  console.log(chr);
+});
+ +

Typisierte Arrays

+ +

JavaScript typisierte Arrays sind Array-ähnliche Objekte und stellen einen Mechanismus für den Zugriff auf Raw-Binärdaten zur Verfügung. Wie bereits erklärt, passen {{jsxref("Array")}} Objekte ihre Grösse dynamisch an und können beliebige Werte enthalten. JavaScript Engines führen Optimierungen durch, damit diese Arrays schneller sind. Je stärker Web-Applikationen werden mit Features wie Audio und Video Manipulation, Zugriff auf Raw Daten mit WebSockets und so weiter, ist es hilfreich, wenn JavaScript Code einfach und schnell Raw Binärdaten in typisierten Arrays manipulieren kann.

+ +

Buffers und Views: Typisierte Array Architektur

+ +

Um maximale Flexibilität und Effizienz zu erreichen, werden typisierte Arrays in JavaScript auf Buffers und Views aufgeteilt. Ein Buffer (implementiert durch das {{jsxref("ArrayBuffer")}} Objekt) ist ein Objekt, welches einen Block Daten repräsentiert; es hat kein Format und keine Mechanismen für den Zugriff auf Inhalte. Um auf den Speicher in einem Buffer zuzugreifen, wird eine View benötigt. Eine View stellt einen Kontext — einen Datentyp, Start-Offset und eine Anzahl Elemente — zur Verfügung, welcher die Daten in einen typisierten Array verwandelt.

+ +

Typed arrays in an ArrayBuffer

+ +

ArrayBuffer

+ +

Der {{jsxref("ArrayBuffer")}} ist ein Datentyp, welcher für die Darstellung von generischen Binär-Daten-Buffer mit einer fixen Grösse. Der Inhalt eines ArrayBuffer kann nicht direkt manipuliert werden; stattdessen kann eine typisierte Array-View oder eine {{jsxref("DataView")}} erstellt werden, welches den Buffer in einem spezifischen Format darstellt, welche dann für das Lesen und Schreiben der Inhalte auf dem Buffer verwendet werden kann.

+ +

Typisierte Array-Views

+ +

Typisierte Array-Views haben selbstbeschreibende Namen und stellen Views für alle geläufigen numerischen Typen, wie Int8, Uint32, Float64 und so weiter, zur Verfügung. Es gibt ein spezielles typisiertes Array: Uint8ClampedArray. Es klemmt (clamps) zwischen 0 und 255. Dies ist hilfreich für Canvas Datenverarbeitung, zum Beispiel.

+ +

{{page("/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray", "TypedArray_objects")}}

+ +

Für weitere Informationen, siehe JavaScript Typisierte Arrays und die Referenzdokumentation für die unterschiedlichen {{jsxref("TypedArray")}} Objekte.

+ +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}

diff --git a/files/de/web/javascript/guide/keyed_collections/index.html b/files/de/web/javascript/guide/keyed_collections/index.html new file mode 100644 index 0000000000..a9b501da9e --- /dev/null +++ b/files/de/web/javascript/guide/keyed_collections/index.html @@ -0,0 +1,157 @@ +--- +title: Collections mit Schlüssel +slug: Web/JavaScript/Guide/Keyed_collections +tags: + - Collections + - Guide + - JavaScript + - Map + - 'l10n:priority' + - set +translation_of: Web/JavaScript/Guide/Keyed_collections +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}
+ +

Dieses Kapitel gibt eine Einleitung in Sammlungen von Daten, welche mit einem Schlüssel verknüpft werden. Map und Set Objekte enthalten Elemente, die in der Reihenfolge ihres Einfügens iterierbar sind.

+ +

Maps

+ +

Map Objekt

+ +

ECMAScript 2015 führt eine neue Datenstruktur ein, um Werte auf Werte zu abbildet. Ein {{jsxref("Map")}} Objekt ist eine einfache Schlüssel/Werte-Abbildung und man kann über die Element in der Einfügereihenfolge iterieren.

+ +

Das folgende Beispiel zeigt einige Basisoperationen mit einer Map.  Für mehr Beispiele und die komplette API siehe zudem die Referenzseite {{jsxref("Map")}}. Man kann eine {{jsxref("Statements/for...of","for...of")}} Schleife benutzen, um ein Array von [key, value] für jede Iteration zurückzugeben.

+ +
var sayings = new Map();
+sayings.set('dog', 'woof');
+sayings.set('cat', 'meow');
+sayings.set('elephant', 'toot');
+sayings.size; // 3
+sayings.get('fox'); // undefined
+sayings.has('bird'); // false
+sayings.delete('dog');
+sayings.has('dog'); // false
+
+for (var [key, value] of sayings) {
+  console.log(key + ' goes ' + value);
+}
+// "cat goes meow"
+// "elephant goes toot"
+
+sayings.clear();
+sayings.size; // 0
+
+ +

Object und Map im Vergleich

+ +

Traditionell werden {{jsxref("Object", "Objekte", "", 1)}} eingesetzt, um Strings auf Werte abzubilden. Objekte erlauben es Werte zu Schlüsseln zu setzen, diese Werte abzufragen, Schlüssel zu löschen und erkennen, ob etwas zu einem Schlüssel gespeichert wurde. Map Objekte haben ein paar Vorteile, was sie zu besseren Abbildungen macht.

+ + + +

Diese drei Tipps können bei der Entscheidung für eine Map oder ein Object helfen:

+ + + +

WeakMap Objekte

+ +

Das {{jsxref("WeakMap")}} Objekt ist eine Collection von Schlüssel/Werte-Paaren, wobei der Schlüssel nur ein Objekt sein kann und die Werte willkürliche Werte sein können. Die Objektreferenzen in den Schlüsseln werden weakly gehalten, was bedeutet, dass diese Referenz ein Ziel des Speicherbereinigung (Garbage Collectors (GC)) wird, wenn keine andere Referenz mehr auf dieses Objekt referenziert. Die WeakMap API ist die gleiche wie die Map API.

+ +

Einen Unterschied zu Map Objekten ist, dass WeakMap Schlüssel nicht aufzählbar sind (z. B. gibt es keine Methode, die eine Liste von Schlüsseln zurückgibt). Wenn dies der Fall wäre, würde die Liste vom Zustand der Speicherbereinigung abhängen, was zu Nicht-Determinismus führen würde.

+ +

Für mehr Informationen, Beispiele und "Warum WeakMap" auf der {{jsxref("WeakMap")}} Referenzseite.

+ +

Ein Einsatzgebiet für WeakMaps ist der Einsatz für Private Daten oder das Verbergen von Implementierungsdetails. Das folgende Beispiel ist von Nick Fitzgeralds Blogpost "Hiding Implementation Details with ECMAScript 6 WeakMaps". Die privaten Daten und Methoden, die zu dem Objekt gehören, werden in dem WeakMap Objekt privates gespeichert. Alles offene auf der Instanz und dem Prototyp ist Öffentlich; alles andere ist von Außen nicht erreichbar, weil privates vom Modul nicht exportiert wird.

+ +
const privates = new WeakMap();
+
+function Public() {
+  const me = {
+    // Private data goes here
+  };
+  privates.set(this, me);
+}
+
+Public.prototype.method = function() {
+  const me = privates.get(this);
+  // Do stuff with private data in `me`...
+};
+
+module.exports = Public;
+
+ +

Sets

+ +

Set Objekte

+ +

{{jsxref("Set")}} Objekte sind Collectionen mit Werten. Man kann über die Elemente in der Einfügereihenfolge iterieren. Ein Wert in einem Set kann nur einmal existieren und ist einzigartig in einer Set Collection.

+ +

Das folgende Beispiel zeigt einige Basisoperationen mit einem Set. Für mehr Beispiele und die komplette API siehe auf der {{jsxref("Set")}} Referenzseite nach.

+ +
var mySet = new Set();
+mySet.add(1);
+mySet.add('some text');
+mySet.add('foo');
+
+mySet.has(1); // true
+mySet.delete('foo');
+mySet.size; // 2
+
+for (let item of mySet) console.log(item);
+// 1
+// "some text"
+
+ +

Konvertierung zwischen Arrays und Sets

+ +

Man kann ein {{jsxref("Array")}} von einem Set erstellen, indem {{jsxref("Array.from")}} oder der spread Operator eingesetzt wird. Zudem akzeptiert der Set Konstruktor ein Array, um es in die andere Richtung zu konvertieren. Wichtig ist aber, dass Set Objekte Werte nur einmalig Speichern, so dass jedes Elementduplikat aus dem Array beim Konvertieren gelöscht wird.

+ +
Array.from(mySet);
+[...mySet2];
+
+mySet2 = new Set([1, 2, 3, 4]);
+
+ +

Array und Set im Vergleich

+ +

Traditionell wird eine Menge von Objekten in vielen Situationen in JavaScript in Arrays gespeichert. Das neue Set Objekt hat aber einige Vorteile:

+ + + +

WeakSet Objekte

+ +

{{jsxref("WeakSet")}} Objekte sind Collections von Objekten. Ein Objekt in einer WeakSet gibt es nur einmal; es ist einzigartig in der WeakSet Collection und Objekte sind nicht aufzählbar.

+ +

Die Hauptunterschiede zu einem {{jsxref("Set")}} Objekt sind:

+ + + +

Die Einsatzgebiete von WeakSet Objekten sind begrenzt. Sie erzeugen keine Speicherlecks, so dass sie sicher DOM Elemente enthalten können, um sie zum Beispiel zu verfolgen.

+ +

Schlüssel- und Wertegleichheit von Map und Set

+ +

Beide, die Schlüsselgleichheit von Map Objekten und die Wertegleichheit von Set Objekten basieren auf dem "same-value-zero Algorithmus":

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Indexed_Collections", "Web/JavaScript/Guide/Working_with_Objects")}}

diff --git a/files/de/web/javascript/guide/kontrollfluss_und_fehlerbehandlung/index.html b/files/de/web/javascript/guide/kontrollfluss_und_fehlerbehandlung/index.html new file mode 100644 index 0000000000..97dbba8b3e --- /dev/null +++ b/files/de/web/javascript/guide/kontrollfluss_und_fehlerbehandlung/index.html @@ -0,0 +1,430 @@ +--- +title: Kontrollfluss und Fehlerbehandlung +slug: Web/JavaScript/Guide/Kontrollfluss_und_Fehlerbehandlung +tags: + - Beginner + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammatik_und_Typen", "Web/JavaScript/Guide/Schleifen_und_Iterationen")}}
+ +

JavaScript unterstützt eine Menge von Anweisungen, speziell um Verlaufs-Anweisungen zu kontrollieren, welches eine großartige Methode ist um Interaktivität in deine Anwendung einzuarbeiten. Dieses Kapitel liefert dir ein Überblick über diese Anweisungen.

+ +

Die JavaScript Referenzen beinhalten umfassende Details über die Anweisungen in diesem Kapitel. Das Semikolon (;) als Zeichen wird genutzt um Anweisungen im JavaScript Code einzuteilen.

+ +

Jeder JavaScript Ausdruck ist auch eine Anweisung. Schau ebenfalls in Ausdrücke und Operatoren, um komplette Informationen über Ausdrücke zu erhalten.

+ +

Block-Anweisungen

+ +

Das einfachste Statement ist das Block-Statement, welches genutzt wird um Anweisungen zu gruppieren. Dieser Block wird von einem Paar geschweiften Klammer umschlossen:

+ +
{
+  statement_1;
+  statement_2;
+  .
+  .
+  .
+  statement_n;
+}
+
+ +

Beispiele

+ +

Block-Statements werden meistens mit Kontrollfluss-Statements genutzt (z. B. if, for, while).

+ +
while (x < 10) {
+  x++;
+}
+
+ +

Hier ist, { x++; } das Block-Statement.

+ +

Wichtig: JavaScript hat vor ECMAScript2015 keine Block-Scopes. Variablen, die in einem Block deklariert werden, gehören zu der Funktion oder dem Skript und das Beschreiben der Variablen führt dazu, dass diese über den Block hinaus verfügbar ist. In anderen Worten, Block-Statements definieren keinen Scope. Alleinstehende Blöcke in JavaScript können komplett andere Ergebnisse erzeugen als in C oder Java. Zum Beispiel:

+ +
var x = 1;
+{
+  var x = 2;
+}
+console.log(x); // outputs 2
+
+ +

Hier wird 2 ausgegeben, weil var x innerhalb des Blocks im gleichen Scope ist wie das var x vor dem Block. In C oder Java hätte der selbe Code 1 ausgegeben.

+ +

Seit ECMAScript2015 sind let und const Variablendeklarationen, die an den Block gebunden sind. Siehe dazu auch die Referenzseiten {{jsxref("Statements/let", "let")}} und {{jsxref("Statements/const", "const")}} an.

+ +

Bedingte Statements

+ +

Ein bedingtes Statement ist eine Menge von Befehlen, die ausgeführt werden, wenn eine Bedingung wahr ist. JavaScript unterstützt zwei bedingte Statements: if...else und switch.

+ +

if...else Anweisungen

+ +

if wird eingesetzt um Statements auszuführen, wenn eine logische Bedingung wahr wird. Mit der optionalen else-Klausel werden Statements ausgeführt, wenn die Bedingung falsch ist. Ein if-Block sieht folgendermaßen aus:

+ +
if (bedingung) {
+  statement_1;
+} else {
+  statement_2;
+}
+ +

Hier kann die Bedingung ein Ausdruck sein, der zu true oder false ausgewertet wird. Siehe Boolean nach, um zu erfahren, was zu true und was zu false ausgewertet wird. Wenn bedingung zu true ausgewertet wird, wird statement_1 ausgeführt. Andernfalls wird statement_2 ausgeführt. statement_1 und statement_2 können beliebige Statements sein, auch weitere if-Statements.

+ +

Man kann zudem Statements mit else if konstruieren, um mehrere Bedingungen sequentiell zu testen:

+ +
if (bedingung_1) {
+  statement_1;
+} else if (bedingung_2) {
+  statement_2;
+} else if (bedingung_n) {
+  statement_n;
+} else {
+  statement_last;
+}
+
+ +

Um mehrere Statements auszuführen, werden diese in Blockstatements gruppiert ({ ... }). Generell ist es guter Stil immer Block-Statements zu benutzen, besonders bei verschachtelten if-Statements.

+ +
if (bedingung) {
+  statement_1_runs_if_condition_is_true;
+  statement_2_runs_if_condition_is_true;
+} else {
+  statement_3_runs_if_condition_is_false;
+  statement_4_runs_if_condition_is_false;
+}
+
+ +

Es ist ratsam, keine einfachen Zuweisungen in Bedingungen zu verwenden, da die Zuordnung mit der Prüfung auf Gleichheit verwechselt werden kann, wenn man über den Code schaut. Verwenden Sie zum Beispiel den folgenden Code nicht:

+ +
if (x = y) {
+  /* statements here */
+}
+
+ +

Wenn eine Zuweisung in einer Bedingung benötigt wird, ist es verbreitet diese in weitere runde Klammeren zu schreiben. Zum Beispiel:

+ +
if ((x = y)) {
+  /* statements here */
+}
+
+ +

Falsy Werte

+ +

Die folgenden Werte werden zu false ausgewertet (auch bekannt als {{Glossary("Falsy")}} Werte):

+ + + +

Alle anderen Werte, auch alle Objekte, werden zu true ausgewertet, wenn sie als Bedingung eingesetzt werden.

+ +

Es ist jedoch etwas verwirrend mit den primitiven boolean Werten true und false und den Werten des {{jsxref("Boolean")}}-Objektes, wie folgendes Beispiel zeigt:

+ +
var b = new Boolean(false);
+if (b)          // Die Bedingung wird zu true ausgewertet.
+if (b == true)  // Die Bedingung wird zu false ausgewertet.
+ +

Beispiel

+ +

Im folgenden Beispiel gibt die Funktion checkData true zurück, wenn die Anzahl der Zeichen in einem Text Objekt drei ist. Andernfalls wird ein Alert angezeigt, und false zurückgegeben.

+ +
function checkData() {
+  if (document.form1.threeChar.value.length == 3) {
+    return true;
+  } else {
+    alert("Enter exactly three characters. " +
+    document.form1.threeChar.value + " is not valid.");
+    return false;
+  }
+}
+
+ +

switch Statement

+ +

Ein switch Statement erlaubt es einen Ausdruck auszuwerten und das Resultat zu einem passenden Fall-Label (case-Label ) zuzuordnen. Wenn ein passendes Fall-Label gefunden wird, werden die zugehörigen Statements ausgeführt. Ein switch Statement sieht wie folgt aus:

+ +
switch (ausdruck) {
+  case label_1:
+    statements_1
+    [break;]
+  case label_2:
+    statements_2
+    [break;]
+    ...
+  default:
+    statements_def
+    [break;]
+}
+
+ +

Das Programm sucht als erstes nach eine case-Klausel mit einem Label, welches mit dem Wert des Ausgewerteten Ausdrucks übereinstimmt und gibt die Kontrolle zu dieser Klausel, was bedeutet, dass die zugehörigen Statements ausgeführt werden. Wenn kein passendes Label gefunden wird, sucht das Programm nach der optionalen default-Klausel und gibt die Kontrolle an diese, was bedeutet, dass die zugehörigen Statements ausgeführt werden. Wenn keine default-Klausel vorhanden ist, wird das switch beendet und das nächste Statement wird ausgeführt. Laut Konventionen ist die default-Klausel die letzte Klausel, das muss aber nicht immer so sein.

+ +

Das optionale break Statement, welches in jeder case-Klausel eingesetzt ist, sorgt daführ, dass nach der Klausel das switch Statement beendet wird und das Programm mit dem nachfolgenden Statement weiter macht. Wenn break weggelassen wird, wird das Programm mit dem nächsten Statement im switch weitermachen, was dazu führt, dass alle nachlogenden case-Klauseln und die optionale default-Klausel mit ausgeführt werden.

+ +

Beispiel

+ +

Im folgenden Beispiel wird der case "Bananas" ausgeführt, wenn fruittype zu "Bananas" ausgewertet wird. Die break Statements bewirken, dass das switch beendet wird und das nach switch stehende Statement ausgeführt wird. Wird break im case "Bananas" weggelassen, so wird der case "Cherries" mit ausgeführt.

+ +
switch (fruittype) {
+  case 'Oranges':
+    console.log('Oranges are $0.59 a pound.');
+    break;
+  case 'Apples':
+    console.log('Apples are $0.32 a pound.');
+    break;
+  case 'Bananas':
+    console.log('Bananas are $0.48 a pound.');
+    break;
+  case 'Cherries':
+    console.log('Cherries are $3.00 a pound.');
+    break;
+  case 'Mangoes':
+    console.log('Mangoes are $0.56 a pound.');
+    break;
+  case 'Papayas':
+    console.log('Mangoes and papayas are $2.79 a pound.');
+    break;
+  default:
+   console.log('Sorry, we are out of ' + fruittype + '.');
+}
+console.log("Is there anything else you'd like?");
+ +

Statements zur Fehler- bzw. Ausnahmebehandlung

+ +

Man kann mit dem throw Statement Fehler werfen (erzeugen) und diese mit dem Einsatz des try...catch Statements auffangen und verarbeiten.

+ + + +

Ausnahmetypen

+ +

Jedes Objekt in JavaScript kann als Fehler bzw. Ausnahme geworfen werden. Nicht alle Fehlerobjekte müssen auf die gleiche Art und Weise erstellt worden sein. Trotz des häufig Einsatzes von Zahlen oder Strings als Ausnahmen ist es deutlich effektiver die speziell für Ausnahmen erstellten Typen zu benutzen:

+ + + +

throw Statement

+ +

Das throw Statement wird benutzt, um eine Exception (Ausnahme / Fehler) zu werfen. Wenn eine Exception geworfen wird, so wird ein Ausdruck spezifiziert, welcher den Wert, welcher geworfen wird, spezifiziert:

+ +
throw ausdruck;
+
+ +

Man kann jeden Ausdruck werfen, nicht nur Ausdrücke eines bestimmten Typs. Der folgende Code wirft mehrere Ausnahmen verschiedenen Typs:

+ +
throw "Error2";   // String type
+throw 42;         // Number type
+throw true;       // Boolean type
+throw {toString: function() { return "I'm an object!"; } };
+
+ +
Notiz: Man kann ein Objekt beim Werfen einer Exception spezifizieren. Im catch Block können die Eigenschaften des Objektes referenziert werden.
+ +
// Erstellt ein Objekt vom Typ UserException
+function UserException (message){
+  this.message=message;
+  this.name="UserException";
+}
+
+// Macht die Konvertierung der Exception in einen schönen String, wenn die Exception
+// als String genutzt werden soll.
+// (z. B. in der Fehlerconsole)
+UserException.prototype.toString = function () {
+  return this.name + ': "' + this.message + '"';
+}
+
+// Erstellt eine Instanz der UserException und wirft diese
+throw new UserException("Value too high");
+ +

try...catch Statement

+ +

Das try...catch Statement markiert einen Block von Statements, welcher versucht wird auszuführen, und einen oder mehrere Blöcke welche auf geworfene Exceptions abfangen. Wenn eine Exception geworfen wird, fängt das try...catch Statements diese ab.

+ +

Das try...catch Statement besteht aus einem try Block, welcher ein oder mehrere Statements enthält, und null oder mehr catch Blöcken, welche Statements spezifizieren, welche eine im try Block geworfene Exception abfangen und behandeln. Das Statement versucht den try Block erfolgreich abzuarbeiten und wenn dieser nicht erfolgreich ist, wird die Kontrolle an den catch Block gegeben. Wenn ein Statement in dem try Block (oder eine im try Block aufgerufene Funktion) eine Exception wirft, wird der Kontrollfluss sofort an den catch Block übergeben. Wenn keine Exception im try Block geworfen wird, wird der catch Block übersprungen. Der optionale finally Block wird nach dem try und nach dem catch Block ausgeführt, bevor das auf das try...catch Statement folgenden Statement ausgeführt wird.

+ +

Das Folgende Beispiel benutzt ein try...catch Statement. Das Beispiel ruft eine Funktion auf, welche einen Monatsnamen aus einen Array zurückgibt, je nachdem, welcher Wert übergeben wurde. Wenn der übergebene Wert keine korrekte Monatsnummer ist (1 - 12), dann wird eine Exception mit dem Wert "InvalidMonthNo" geworfen und die Statements im catch Block setzen die monthName Variable auf unknown.

+ +
function getMonthName (mo) {
+  mo = mo-1; // Justiert Monatsnummer zu Arrayindex (1=Jan, 12=Dec)
+  var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul",
+                "Aug","Sep","Oct","Nov","Dec"];
+  if (months[mo] != null) {
+    return months[mo];
+  } else {
+    throw "InvalidMonthNo"; // throw Schlüsselwort wird hier benutzt
+  }
+}
+
+try { // statements to try
+  monthName = getMonthName(myMonth); // Funktion die Exceptions werfen kann
+}
+catch (e) {
+  monthName = "unknown";
+  logMyErrors(e); // Gibt Exception Objekt weiter für Fehlerbehandlung
+}
+
+ +

Der catch Block

+ +

Man kann einen catch Block einsetzen, um alle Exceptions, die im try Block generiert werden, zu verarbeiten.

+ +
catch (catchID) {
+  statements
+}
+
+ +

Der catch Block spezifiziert einen Variable (catchID im voranstehenden Syntaxbeispiel), welcher den Wert des throw Statements enthält. Man kann über diese Variable Informationen über die geworfene Exception abfragen. JavaScript erstellt diese Variable, wenn der Programmfluss in den catch Block geht. Die Variable existiert nur in dem catch Block. Nach dem beenden des catch Blocks ist die Variable nicht mehr verfügbar.

+ +

Im nächsten Beispeil wird eine Exception geworfen. Wenn die Exception geworfen wird, wird der Programmfluss in den catch Block gegeben.

+ +
try {
+  throw "myException" // Erstellt eine Exception
+}
+catch (e) {
+  // Statements, die die Exception verarbeiten
+  logMyErrors(e) // Verarbeitet Exception Objekt zur Fehlerbehandlung
+}
+
+ +

Der finally Block

+ +

Der finally Block enthält Statements, welche nach dem try und catch Block ausgeführt werden, bevor das Statement nach dem try...catch Statement ausgeführt wird. Der finally Block wird ausgeführt, egal ob eine Exception geworfen wird oder nicht. Wenn eine Exception geworfen wird, wird der finally auch ausgeführt, wenn kein catch die Exception abfängt.

+ +

Man kann den finally Block benutzen, um Skripte fehlertoleranter zu gestalten. Zum Beispiel kann eine Ressource im finally Block geschlossen werden. Das Folgende Beispiel öffnet eine Datei und führt Statements aus, um die Datei zu benutzen (Serverseitiges JavaScript erlaubt Zugriffe auf Dateien). Wenn eine Exception geworfen wird, während die Datei geöffnet ist, sorgt der finally Block dafür, dass die Datei wieder geschlossen wird.

+ +
openMyFile();
+try {
+  writeMyFile(theData); //Das kann Exceptions werfen
+} catch(e) {
+  handleError(e); // Wenn eine Exception geworfen wird, wird sie hier verarbeitet
+} finally {
+  closeMyFile(); // Schließt immer die Ressource
+}
+
+ +

Wenn der finally Block einen Rückgabewert definiert, ist dieser der Rückgabewert des try-catch-finally Prozedur, unabhängig davon, ob return Statements im try und catch Block verwendet werden.

+ +
function f() {
+  try {
+    console.log(0);
+    throw "bogus";
+  } catch(e) {
+    console.log(1);
+    return true; // Dieses return Statement is überflüssig
+                 // weil im finally Block ebenfalls eins vorhanden ist
+    console.log(2); // wird niemals erreicht
+  } finally {
+    console.log(3);
+    return false; // überschreibt früheres return Statements
+    console.log(4); // wird niemals erreicht
+  }
+  // false wird jetzt zurückgegeben
+  console.log(5); // wird niemals erreicht
+}
+f(); // alerts 0, 1, 3; returns false
+
+ +

Das Überschreiben des Rückgabewertes durch den finally Block überschreibt auch geworfene Exceptions, wenn diese im catch geworfen werden.

+ +
function f() {
+  try {
+    throw "bogus";
+  } catch(e) {
+    console.log('caught inner "bogus"');
+    throw e; // Dieses throw Statement is überflüssig
+             // weil im finally Block ein return vorkommt
+  } finally {
+    return false; // Überschreibt das vorherige "throw"
+  }
+  // false wird zurückgegeben
+}
+
+try {
+  f();
+} catch(e) {
+  // Dieser bereich wird nie erreicht, weil
+  // die Exception durch das return im
+  // finally block überschrieben wird.
+  console.log('caught outer "bogus"');
+}
+
+// OUTPUT
+// caught inner "bogus"
+ +

Verschachtelte try...catch Statements

+ +

Man kann mehrere try...catch Statements ineinander verschachteln. Wenn ein inneres try...catch Statements keinen catch Block hat, wird ein äußeres try...catch Statement mit einem catch Block eine Exception auffangen. Mehr Informationen gibt es im Kapitel Verschachtelte try-Blöcke auf der try...catch Seite.

+ +

Nützliche Verwendung des Error Objekts

+ +

Abhängig vom der Art des Fehlers, möchte man die Möglichkeit haben einen Namen und eine Fehlernachricht zu vergeben. 'name' und 'message' Eigenschaften sind generell durch die Klasse Error (z. B. DOMException oder Error) unterstützt. Die 'message' Eigenschaft ist dabei eine String-Repräsentation des Fehlers, so wie sie bei der Konvertierung des Objektes zu einem String benötigt wird.

+ +

Wenn man beim Werfen von eigenen Exceptions die Vorteile dieser Eigenschaften nutzen möchte (wenn zum Beipsiel der catch Block nicht zwischen eigenen und System Exceptions unterscheidet), kann der Konstruktor von Error benutzt werden. Zum Beispiel:

+ +
function doSomethingErrorProne () {
+  if (ourCodeMakesAMistake()) {
+    throw (new Error('The message'));
+  } else {
+    doSomethingToGetAJavascriptError();
+  }
+}
+....
+try {
+  doSomethingErrorProne();
+}
+catch (e) {
+  console.log(e.name); // logs 'Error'
+  console.log(e.message); // logs 'The message' or a JavaScript error message)
+}
+ +

Promises

+ +

Mit ECMAScript 6 hat JavaScript die Unterstützung für {{jsxref("Promise")}} Objekte bekommen, welche zum Steuern von asynchronen Operationen genutzt wird.

+ +

Ein Promise ist in einem der folgenen Status:

+ + + +

+ +

Ein Bild mit XHR laden

+ +

Ein einfaches Beispiel für den Einsatz von Promise und XMLHttpRequest ist das Laden eines Bildes (Siehe MDN GitHub js-examples Repository; man kann es hier auch in Aktion sehen). Jeder Schritt ist Kommentiert und erlaubt es der Architektur des Promise und XHR zu folgen. Hier ist die unkommentierte Version, welche den Promise Ablauf zeigt, zu sehen, so dass man eine Idee davon bekommt.

+ +
function imgLoad(url) {
+  return new Promise(function(resolve, reject) {
+    var request = new XMLHttpRequest();
+    request.open('GET', url);
+    request.responseType = 'blob';
+    request.onload = function() {
+      if (request.status === 200) {
+        resolve(request.response);
+      } else {
+        reject(Error('Image didn\'t load successfully; error code:'
+                     + request.statusText));
+      }
+    };
+    request.onerror = function() {
+      reject(Error('There was a network error.'));
+    };
+    request.send();
+  });
+}
+ +

Für deteiliertere Informationen, kann man sich die {{jsxref("Promise")}} Referenz Seite und den Using Promises Guide anschauen.

+ +
{{PreviousNext("Web/JavaScript/Guide/Grammatik_und_Typen", "Web/JavaScript/Guide/Schleifen_und_Iterationen")}}
diff --git a/files/de/web/javascript/guide/meta_programming/index.html b/files/de/web/javascript/guide/meta_programming/index.html new file mode 100644 index 0000000000..691f5b05a6 --- /dev/null +++ b/files/de/web/javascript/guide/meta_programming/index.html @@ -0,0 +1,265 @@ +--- +title: Meta programming +slug: Web/JavaScript/Guide/Meta_programming +tags: + - Guide + - JavaScript + - Proxy + - Reflect + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Meta_programming +--- +
{{jsSidebar("JavaScript Guide")}} {{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +

Beginnend mit ECMAScript 2015 hat JavaScript Unterstützung für {{jsxref("Proxy")}} and {{jsxref("Reflect")}} Objekte erhalten, welche das Abfangen und Definieren von benutzerdefinierten Verhaltens für grundlegenden Sprachoperation erlaubt (z. B. Eigenschaftensuche, Zuweisung, Aufzählung, Funktionsaufruf usw.). Mit der Hilfe dieser beiden Objekte ist es möglich auf der Metaebene von JavaScript zu programmieren.

+ +

Proxies

+ +

Eingeführt in ECMAScript 6 erlaubt das {{jsxref("Proxy")}} Objekt das Abfangen und Definieren von benutzerdefinierten Verhaltens für bestimmte Operationen. Zum Beispiel um die Eigenschaft eines Objektes zu erhalten:

+ +
var handler = {
+  get: function(target, name) {
+    return name in target ? target[name] : 42;
+  }
+};
+
+var p = new Proxy({}, handler);
+p.a = 1;
+console.log(p.a, p.b); // 1, 42
+
+ +

Das Proxy Objekt definiert einen Ziel (target) (hier ein leeres Objekt) und einen handler (Verhaltens) Objekt in dem ein get Trap implementiert ist. In diesem Beispiel wird kein undefined zurückgegeben, wenn Eigenschaften nicht definiert sind. Stattdessen wird die Zahl 42 zurückgegeben.

+ +

Weitere Beispiele sind auf der {{jsxref("Proxy")}} Referenzseite verfügbar.

+ +

Terminologie

+ +

Die folgenden Terme werden im Zusammenhang mit der Funktionalität von Proxies verwendet.

+ +
+
{{jsxref("Global_Objects/Proxy/handler","Handler","","true")}}
+
Platzhalterobjekt, welches Traps enthält.
+
Traps
+
Die Methoden, die Zugriff auf Eigenschaften unterstützen. Diese sind analog zu Traps in Betriebssystemen.
+
Ziel
+
Objekt, welches vom Proxy virtualisiert wird. Es wird häufig als Speicher-Backend für den Proxy benutzt. Invarianten (Semantik, die unverändert bleiben) bezüglich nicht erweiterbarer Objekteigenschaften oder nicht konfigurierbarer Eigenschaften werden gegen das Ziel verifiziert.
+
Invarianten
+
Semantiken, die bei der Implementierung von benutzerdefinierten Operationen unverändert bleiben, werden als Invarianten bezeichnet. Wenn Sie gegen die Invarianten eines Handlers verstoßen, wird ein {{jsxref("TypeError")}} erzeugt.
+
+ +

Handlers und Traps

+ +

Die Folgende Tabelle fasst die verfügbaren Traps von Proxy Objekten zusammen. Siehe auf der Referenzseite für detailliertere Erklärungen und Beispiele.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Handler / TrapInterceptionsInvarianten
{{jsxref("Global_Objects/Proxy/handler/getPrototypeOf", "handler.getPrototypeOf()")}}{{jsxref("Object.getPrototypeOf()")}}
+ {{jsxref("Reflect.getPrototypeOf()")}}
+ {{jsxref("Object/proto", "__proto__")}}
+ {{jsxref("Object.prototype.isPrototypeOf()")}}
+ {{jsxref("Operators/instanceof", "instanceof")}}
+
    +
  • Die getPrototypeOf Methode muss ein Objekt or null zurückgeben.
  • +
  • Wenn target nicht erweiterbar ist, muss die Object.getPrototypeOf(proxy) Methode das gleiche zurückgeben wie Object.getPrototypeOf(target).
  • +
+
{{jsxref("Global_Objects/Proxy/handler/setPrototypeOf", "handler.setPrototypeOf()")}}{{jsxref("Object.setPrototypeOf()")}}
+ {{jsxref("Reflect.setPrototypeOf()")}}
Wenn target nicht erweiterbar ist, muss der prototype Parameter der gleiche Wert sein wie Object.getPrototypeOf(target).
{{jsxref("Global_Objects/Proxy/handler/isExtensible", "handler.isExtensible()")}}{{jsxref("Object.isExtensible()")}}
+ {{jsxref("Reflect.isExtensible()")}}
Object.isExtensible(proxy) muss den gleichen Wert wie Object.isExtensible(target) zurückgeben.
{{jsxref("Global_Objects/Proxy/handler/preventExtensions", "handler.preventExtensions()")}}{{jsxref("Object.preventExtensions()")}}
+ {{jsxref("Reflect.preventExtensions()")}}
Object.preventExtensions(proxy) gibt nur true zurück, wenn Object.isExtensible(proxy) false ist.
{{jsxref("Global_Objects/Proxy/handler/getOwnPropertyDescriptor", "handler.getOwnPropertyDescriptor()")}}{{jsxref("Object.getOwnPropertyDescriptor()")}}
+ {{jsxref("Reflect.getOwnPropertyDescriptor()")}}
+
    +
  • getOwnPropertyDescriptor muss ein Objekt oder undefined zurückgeben.
  • +
  • Eine Eigenschaft kann nicht als nichtexistent erkannt werden, wenn sie als nicht konfigurierbare Eigenschaft des Zielobjektes existiert.
  • +
  • Eine Eigenschaft kann nicht als nichtexistent erkannt werden, wenn sie als Eigenschaft des Zielobjektes existiert und das Zielobjekt nicht erweiterbar ist.
  • +
  • Eine Eigenschaft kann nicht als existent erkannt werden, wenn sie nicht als Eigenschaft des Zielobjektes existiert und das Zielobjekt nicht erweiterbar ist.
  • +
  • Eine Eigenschaft kann nicht als nicht konfigurierbar erkannt werden, wenn sie nicht als Eigenschaft des Zielobjektes existiert oder wenn sie als konfigurierbare Eigenschaft des Zielobjekt existiert.
  • +
  • Das Ergebnis von Object.getOwnPropertyDescriptor(target) kann dem Zielobjekt mit Object.defineProperty übergeben werden ohne, dass ein Fehler erzeugt wird.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/defineProperty", "handler.defineProperty()")}}{{jsxref("Object.defineProperty()")}}
+ {{jsxref("Reflect.defineProperty()")}}
+
    +
  • Eine Eigenschaft kann nicht hinzugefügt werden, wenn das Zielobjekt nicht erweiterbar ist.
  • +
  • Eine Eigenschaft kann nicht hinzugefügt werden oder zu nicht konfigurierbar geändert werden, wenn es nicht als nicht konfigurierbares Eigenschaft im Zielobjekt existiert.
  • +
  • Eine Eigenschaft darf nicht nicht konfigurierbar sein, wenn die zugehörige konfigurierbare Eigenschaft im Zielobjekt existiert.
  • +
  • Wenn eine Eigenschaft eine zugehörige Eigenschaft im Zielobjekt hat, so wird Object.defineProperty(target, prop, descriptor) keinen Fehler erzeugen.
  • +
  • Im Strict Mode, wird ein falscher Rückgabewert des defineProperty Handler einen {{jsxref("TypeError")}} Erzeugen.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/has", "handler.has()")}}Eigenschaftsabfrage: foo in proxy
+ Vererbte Eigenschaftsabfrage: foo in Object.create(proxy)
+ {{jsxref("Reflect.has()")}}
+
    +
  • Eine Eigenschaft kan nicht als nichtexistent erkannt werden, wenn sie als nicht konfigurierbare Eigenschaft im Zielobjekt existiert.
  • +
  • Eine Eigenschaft kan nicht als nichtexistent erkannt werden, wenn sie als Eigenschaft im Zielobjekt existiert und das Zielobjekt nicht erweiterbar ist.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/get", "handler.get()")}}Eigenschaftszugriff: proxy[foo]and proxy.bar
+ Vererbter Eigenschaftszugriff: Object.create(proxy)[foo]
+ {{jsxref("Reflect.get()")}}
+
    +
  • Der Wert, der für eine Eigenschaft zurückgegeben wird, muss der gleiche sein wie der in der zugehörigen Eigenschaft des Zielobjekts, wenn die Eigenschaft im Zielobjekt nicht überschreibbar und nicht konfigurierbar ist.
  • +
  • Der Wert, der für eine Eigenschaft zurückgegeben wird, muss undefined sein, wenn die zugehörige Eigenschaft im Zielobjekt einen nicht konfigurierbare Zugriffseigenschaft hat, dessen [[Get]] Attribut undefined ist.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/set", "handler.set()")}}Eigenschaftszuweisung: proxy[foo] = bar and proxy.foo = bar
+ Vererbte Eigenschaftszuweisung: Object.create(proxy)[foo] = bar
+ {{jsxref("Reflect.set()")}}
+
    +
  • Der Wert kann nicht zu einem geändert werden, der anders als dem Wert im Zielobjekt ist, wenn die zugehörige Eigenschaft im Zielobjekt eine nicht überschreibbare, nicht konfigurierbare Dateneigenschaft ist.
  • +
  • Der Wert der Eigenschaft kann nicht geändert werden, wenn die zugehörige Eigenschaft im Zielobjekt nicht konfigurierbar ist und das [[Set]] Attribut den Wert undefined hat.
  • +
  • Im Strict Mode, wird ein falscher Rückgabewert des set Handlers einen {{jsxref("TypeError")}} erzeugen.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/deleteProperty", "handler.deleteProperty()")}}Eigenschaft löschen: delete proxy[foo] und delete proxy.foo
+ {{jsxref("Reflect.deleteProperty()")}}
Eine Eigenschaft kann nicht gelöscht werden, Wenn sie als nicht konfigurierbare Eigenschaft im Zielobjekt existiert.
{{jsxref("Global_Objects/Proxy/handler/enumerate", "handler.enumerate()")}}Eigenschaft aufzählen (enumeration) / for...in: for (var name in proxy) {...}
+ {{jsxref("Reflect.enumerate()")}}
Die enumerate Methode muss ein Objekt zurückgeben.
{{jsxref("Global_Objects/Proxy/handler/ownKeys", "handler.ownKeys()")}}{{jsxref("Object.getOwnPropertyNames()")}}
+ {{jsxref("Object.getOwnPropertySymbols()")}}
+ {{jsxref("Object.keys()")}}
+ {{jsxref("Reflect.ownKeys()")}}
+
    +
  • Das Ergebnis von ownKeys ist eine Liste.
  • +
  • Der Typ jedes Elements in der Ergebnisliste ist entweder {{jsxref("String")}} oder {{jsxref("Symbol")}}.
  • +
  • Die Ergebnisliste muss alle Schlüssel von nicht konfigurierbaren Eigenschaften des Zielobjektes enthalten.
  • +
  • Wenn das Zielobjekt nicht erweiterbar ist, muss die Ergebnisliste alle Schlüssel des Zielobjektes enthalten und keine anderen Werte.
  • +
+
{{jsxref("Global_Objects/Proxy/handler/apply", "handler.apply()")}}proxy(..args)
+ {{jsxref("Function.prototype.apply()")}} and {{jsxref("Function.prototype.call()")}}
+ {{jsxref("Reflect.apply()")}}
Es gibt keine Invarianten für die handler.apply Methode.
{{jsxref("Global_Objects/Proxy/handler/construct", "handler.construct()")}}new proxy(...args)
+ {{jsxref("Reflect.construct()")}}
Das Ergebnis muss ein Object sein.
+ +

Widerrufbarer Proxy

+ +

Die {{jsxref("Proxy.revocable()")}} Methode wird benutzt, um ein widerrufbares Proxy Objekt zu erstellen. Das bedeutet, dass der Proxy mit der Funktion revoke widerrufen werden kann und der Proxy ausgeschaltet wird. Danach wird jede Operation auf dem Proxy zu einem {{jsxref("TypeError")}} führen.

+ +
var revocable = Proxy.revocable({}, {
+  get: function(target, name) {
+    return '[[' + name + ']]';
+  }
+});
+var proxy = revocable.proxy;
+console.log(proxy.foo); // "[[foo]]"
+
+revocable.revoke();
+
+console.log(proxy.foo);  // TypeError is thrown
+proxy.foo = 1;           // TypeError again
+delete proxy.foo;        // still TypeError
+typeof proxy;            // "object", typeof doesn't trigger any trap
+ +

Reflection

+ +

{{jsxref("Reflect")}} ist ein Standardobjekt welches Methoden unterstützt, welche das Abfragen von JavaScript Operationen erlauben. Die Methoden sind die gleichen wie die eines {{jsxref("Global_Objects/Proxy/handler","Proxy Handlers","","true")}}. Reflect ist kein Funktionsobjekt.

+ +

Reflect hilft beim Weiterleiten von Standardoperationen des Handlers zu dem Zielobjekt.

+ +

Mit bekommt man {{jsxref("Reflect.has()")}} zum Beispiel den in Operator als Funktion:

+ +
Reflect.has(Object, 'assign'); // true
+
+ +

Eine bessere apply Funktion

+ +

In ES5 wird typischerweise die {{jsxref("Function.prototype.apply()")}} Methode genutzt, um eine Funktion mit einem gegebenen this Wert und arguments als Array (oder ein Array-ähnliches Objekt) benutzt.

+ +
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
+ +

Mit {{jsxref("Reflect.apply")}} wird dieses weniger Langatmig und leichter verständlich:

+ +
Reflect.apply(Math.floor, undefined, [1.75]);
+// 1;
+
+Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
+// "hello"
+
+Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index;
+// 4
+
+Reflect.apply(''.charAt, 'ponies', [3]);
+// "i"
+
+ +

Prüfen ob Eigenschaftsdefinitionen erfolgreich waren

+ +

Mit {{jsxref("Object.defineProperty")}}, welche ein Objekt zurück gibt, wenn es erfolgreich war, oder andernfalls ein {{jsxref("TypeError")}} erzeugt, muss man ein {{jsxref("Statements/try...catch","try...catch")}} Block benutzen, um einen Fehler bei der Definition einer Eigenschaft abzufangen. Weil {{jsxref("Reflect.defineProperty")}} einen Boolean als Status zurück gibt, kann man einfach einen {{jsxref("Statements/if...else","if...else")}} Block benutzen:

+ +
if (Reflect.defineProperty(target, property, attributes)) {
+  // success
+} else {
+  // failure
+}
+ +

{{Previous("Web/JavaScript/Guide/Iterators_and_Generators")}}

diff --git a/files/de/web/javascript/guide/mit_objekten_arbeiten/index.html b/files/de/web/javascript/guide/mit_objekten_arbeiten/index.html new file mode 100644 index 0000000000..2448621a4a --- /dev/null +++ b/files/de/web/javascript/guide/mit_objekten_arbeiten/index.html @@ -0,0 +1,506 @@ +--- +title: Mit Objekten arbeiten +slug: Web/JavaScript/Guide/Mit_Objekten_arbeiten +tags: + - Beginner + - Comparing object + - Constructor + - Document + - Guide + - JavaScript + - Object + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Feinheiten_des_Objektmodells")}}
+ +

JavaScript ist nach einem einfachen objekt-basierten Muster entworfen. Ein Objekt ist eine Sammlung von Eigenschaften und eine Eigenschaft ist eine Verbindung von einem Namen und einem Wert. Der Wert einer Eigenschaft kann eine Funktion sein. In diesem Fall wird die Eigenschaft Methode genannt. Zusätzlich zu Objekten, die vom Browser vordefiniert sind, können auch eigene Objekte definiert werden. Dieses Kapitel beschreibt, wie Objekte, Eigenschaften, Funktionen und Methoden benutzt und eigene Objekte erzeugt werden können.

+ +

Objekte Übersicht

+ +

Objekte in JavaScript, wie in vielen anderen Programmiersprachen, können mit Objekten aus dem realen Leben verglichen werden. Das Konzept der Objekte in JavaScript kann mit greifbaren Objekten aus der realen Welt verstanden werden.

+ +

In JavaScript ist ein Objekt eine für sich stehende Einheit mit Eigenschaften und Typ. Vergleichbar mit einer Tasse zum Beispiel. Eine Tasse ist ein Objekt mit Eigenschaften. Eine Tasse hat eine Farbe, ein Design, ein Gewicht, ein Material, aus dem sie erstellt wurde, usw. Ebenso können JavaScript Objekte Eigenschaften besitzen, die Ihre Besonderheiten definieren.

+ +

Objekte und Eigenschaften

+ +

Ein JavaScript Objekt besitzt mit ihm verbundene Eigenschaften. Eine Eigenschaft eines Objekts kann als Variable erklärt werden, die dem Objekt angeheftet ist. Objekteigenschaften sind grundsätzlich das Gleiche wie übliche Variablen ausser der Verknüpfung mit Objekten. Die Eigenschaften eines Objekts definieren seine Charakteristik. Auf die Eigenschaften eines Objekt kann mit einer einfachen Punkt-Notation zugegriffen werden:

+ +
objectName.propertyName
+
+ +

Wie bei allen JavaScript-Variablen sind Objektname (eine normale Variable) und Attribute groß-, und kleinschreibungsabhängig. Ein Attribut wird definiert, indem es einen Wert zugewiesen bekommt. Zum Beispiel: Ein Objekt namens myCar mit den Attributen make, model, und year:

+ +
var myCar = new Object();
+myCar.make = "Ford";
+myCar.model = "Mustang";
+myCar.year = 1969;
+
+ +

Nicht initialisierte Eigenschaften eines Objektes haben den Wert {{jsxref("undefined")}} (nicht {{jsxref("null")}}).

+ +
myCar.color; // undefined
+ +

Eigenschaften von JavaScript-Objekten können auch mit der Klammernotation (für weitere Informationen siehe property accessors). Objekte werden manchmal assoziative Arrays genannt da jede Eigenschaft mit einer Zeichenkette assoziiert ist mit der man auf die Eigenschaft zugreifen kann. Zum Beispiel kann man auf die Eigenschaften des Objekts myCar folgendermassen zugreifen:

+ +
myCar["make"] = "Ford";
+myCar["model"] = "Mustang";
+myCar["year"] = 1969;
+
+ +

Der Name einer Objekteigenschaft kann ein valider JavaScript String sein. Dies kann auch alles sein, was in einen String convertiert werden kann, inklusive eines leeren Strings. Immer, wenn der Name einer Eigenschaft kein valider JavaScript Bezeichner ist (zum Beispiel ein Name mit einem Leerzeichen oder einem minus oder ein Name der mit einer Ziffer beginnt), kann dieses nur über die Klammernotation erreicht werden. Diese Notation ist zusätzlich sehr hilfreich, wenn Namen von Eigenschaften dynamisch ermittelt werden (Wenn die Namen nicht bis zur Laufzeit ermittelt werden können). Im folgenden ein Beispiel:

+ +
// four variables are created and assigned in a single go,
+// separated by commas
+var myObj = new Object(),
+    str = 'myString',
+    rand = Math.random(),
+    obj = new Object();
+
+myObj.type              = 'Dot syntax';
+myObj['date created']   = 'String with space';
+myObj[str]              = 'String value';
+myObj[rand]             = 'Random Number';
+myObj[obj]              = 'Object';
+myObj['']               = 'Even an empty string';
+
+console.log(myObj);
+
+ +

Zu bemerken ist, dass alle Schlüssel in der Klammernotation zum Typ Strings konvertiert werden, weil in JavaScript nur Strings als Schlüssel bei Objekte erlaubt sind. Zum Beispiel wird im orberen Beispiel obj konvertiert wenn es in myObj benutzt wird. JavaScript ruft die obj.toString() Methode auf und benutzt den resultierenden String als neuen Schlüssel.

+ +

Man kann eine Eigenschaft auch erreichen, indem eine Variable vom Typ String benutzt wird:

+ +
var propertyName = 'make';
+myCar[propertyName] = 'Ford';
+
+propertyName = 'model';
+myCar[propertyName] = 'Mustang';
+
+ +

Man kann die Klammernotation mit for...in nutzen, um über alle enumerable (aufzählbaren) Eigenschaften eines Objektes zu iterieren. Um dieses zu zeigen wie das funktioniert, zeigt die folgende Funktion die Eigenschaften eines Objektes, wenn eine Objekt und der Name des Objektes der Funktion als Parameter übergeben werden:

+ +
function showProps(obj, objName) {
+  var result = '';
+  for (var i in obj) {
+    // obj.hasOwnProperty() wird benutzt um Eigenschaften aus der Prototypen-Kette herauszufiltern
+    if (obj.hasOwnProperty(i)) {
+      result += objName + '.' + i + ' = ' + obj[i] + '\n';
+    }
+  }
+  return result;
+}
+
+ +

So gibt der Aufruf showProps(myCar, "myCar") folgenden Rückgabewert zurück:

+ +
myCar.make = Ford
+myCar.model = Mustang
+myCar.year = 1969
+ +

Enumerate the properties of an object

+ +

Starting with ECMAScript 5, there are three native ways to list/traverse object properties:

+ + + +

Before ECMAScript 5, there was no native way to list all properties of an object. However, this can be achieved with the following function:

+ +
function listAllProperties(o) {
+	var objectToInspect;
+	var result = [];
+
+	for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) {
+      result = result.concat(Object.getOwnPropertyNames(objectToInspect));
+	}
+
+	return result;
+}
+
+ +

This can be useful to reveal "hidden" properties (properties in the prototype chain which are not accessible through the object, because another property has the same name earlier in the prototype chain). Listing accessible properties only can easily be done by removing duplicates in the array.

+ +

Creating new objects

+ +

JavaScript has a number of predefined objects. In addition, you can create your own objects. You can create an object using an object initializer. Alternatively, you can first create a constructor function and then instantiate an object invoking that function in conjunction with the new operator.

+ +

Using object initializers

+ +

In addition to creating objects using a constructor function, you can create objects using an object initializer. Using object initializers is sometimes referred to as creating objects with literal notation. "Object initializer" is consistent with the terminology used by C++.

+ +

The syntax for an object using an object initializer is:

+ +
var obj = { property_1:   value_1,   // property_# may be an identifier...
+            2:            value_2,   // or a number...
+            // ...,
+            'property n': value_n }; // or a string
+
+ +

where obj is the name of the new object, each property_i is an identifier (either a name, a number, or a string literal), and each value_i is an expression whose value is assigned to the property_i. The obj and assignment is optional; if you do not need to refer to this object elsewhere, you do not need to assign it to a variable. (Note that you may need to wrap the object literal in parentheses if the object appears where a statement is expected, so as not to have the literal be confused with a block statement.)

+ +

Object initializers are expressions, and each object initializer results in a new object being created whenever the statement in which it appears is executed. Identical object initializers create distinct objects that will not compare to each other as equal. Objects are created as if a call to new Object() were made; that is, objects made from object literal expressions are instances of Object.

+ +

The following statement creates an object and assigns it to the variable x if and only if the expression cond is true:

+ +
if (cond) var x = {greeting: 'hi there'};
+
+ +

The following example creates myHonda with three properties. Note that the engine property is also an object with its own properties.

+ +
var myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}};
+
+ +

You can also use object initializers to create arrays. See array literals.

+ +

Using a constructor function

+ +

Alternatively, you can create an object with these two steps:

+ +
    +
  1. Define the object type by writing a constructor function. There is a strong convention, with good reason, to use a capital initial letter.
  2. +
  3. Create an instance of the object with new.
  4. +
+ +

To define an object type, create a function for the object type that specifies its name, properties, and methods. For example, suppose you want to create an object type for cars. You want this type of object to be called Car, and you want it to have properties for make, model, and year. To do this, you would write the following function:

+ +
function Car(make, model, year) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+}
+
+ +

Notice the use of this to assign values to the object's properties based on the values passed to the function.

+ +

Now you can create an object called mycar as follows:

+ +
var mycar = new Car('Eagle', 'Talon TSi', 1993);
+
+ +

This statement creates mycar and assigns it the specified values for its properties. Then the value of mycar.make is the string "Eagle", mycar.year is the integer 1993, and so on.

+ +

You can create any number of Car objects by calls to new. For example,

+ +
var kenscar = new Car('Nissan', '300ZX', 1992);
+var vpgscar = new Car('Mazda', 'Miata', 1990);
+
+ +

An object can have a property that is itself another object. For example, suppose you define an object called person as follows:

+ +
function Person(name, age, sex) {
+  this.name = name;
+  this.age = age;
+  this.sex = sex;
+}
+
+ +

and then instantiate two new person objects as follows:

+ +
var rand = new Person('Rand McKinnon', 33, 'M');
+var ken = new Person('Ken Jones', 39, 'M');
+
+ +

Then, you can rewrite the definition of Car to include an owner property that takes a person object, as follows:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+}
+
+ +

To instantiate the new objects, you then use the following:

+ +
var car1 = new Car('Eagle', 'Talon TSi', 1993, rand);
+var car2 = new Car('Nissan', '300ZX', 1992, ken);
+
+ +

Notice that instead of passing a literal string or integer value when creating the new objects, the above statements pass the objects rand and ken as the arguments for the owners. Then if you want to find out the name of the owner of car2, you can access the following property:

+ +
car2.owner.name
+
+ +

Note that you can always add a property to a previously defined object. For example, the statement

+ +
car1.color = 'black';
+
+ +

adds a property color to car1, and assigns it a value of "black." However, this does not affect any other objects. To add the new property to all objects of the same type, you have to add the property to the definition of the Car object type.

+ +

Using the Object.create method

+ +

Objects can also be created using the {{jsxref("Object.create()")}} method. This method can be very useful, because it allows you to choose the prototype object for the object you want to create, without having to define a constructor function.

+ +
// Animal properties and method encapsulation
+var Animal = {
+  type: 'Invertebrates', // Default value of properties
+  displayType: function() {  // Method which will display type of Animal
+    console.log(this.type);
+  }
+};
+
+// Create new animal type called animal1
+var animal1 = Object.create(Animal);
+animal1.displayType(); // Output:Invertebrates
+
+// Create new animal type called Fishes
+var fish = Object.create(Animal);
+fish.type = 'Fishes';
+fish.displayType(); // Output:Fishes
+ +

Inheritance

+ +

All objects in JavaScript inherit from at least one other object. The object being inherited from is known as the prototype, and the inherited properties can be found in the prototype object of the constructor. See Inheritance and the prototype chain for more information.

+ +

Indexing object properties

+ +

You can refer to a property of an object either by its property name or by its ordinal index. If you initially define a property by its name, you must always refer to it by its name, and if you initially define a property by an index, you must always refer to it by its index.

+ +

This restriction applies when you create an object and its properties with a constructor function (as we did previously with the Car object type) and when you define individual properties explicitly (for example, myCar.color = "red"). If you initially define an object property with an index, such as myCar[5] = "25 mpg", you subsequently refer to the property only as myCar[5].

+ +

The exception to this rule is objects reflected from HTML, such as the forms array. You can always refer to objects in these arrays by either their ordinal number (based on where they appear in the document) or their name (if defined). For example, if the second <FORM> tag in a document has a NAME attribute of "myForm", you can refer to the form as document.forms[1] or document.forms["myForm"] or document.forms.myForm.

+ +

Defining properties for an object type

+ +

You can add a property to a previously defined object type by using the prototype property. This defines a property that is shared by all objects of the specified type, rather than by just one instance of the object. The following code adds a color property to all objects of type Car, and then assigns a value to the color property of the object car1.

+ +
Car.prototype.color = null;
+car1.color = 'black';
+
+ +

See the prototype property of the Function object in the JavaScript reference for more information.

+ +

Defining methods

+ +

A method is a function associated with an object, or, simply put, a method is a property of an object that is a function. Methods are defined the way normal functions are defined, except that they have to be assigned as the property of an object. See also method definitions for more details. An example is:

+ +
objectName.methodname = functionName;
+
+var myObj = {
+  myMethod: function(params) {
+    // ...do something
+  }
+
+  // OR THIS WORKS TOO
+
+  myOtherMethod(params) {
+    // ...do something else
+  }
+};
+
+ +

where objectName is an existing object, methodname is the name you are assigning to the method, and functionName is the name of the function.

+ +

You can then call the method in the context of the object as follows:

+ +
object.methodname(params);
+
+ +

You can define methods for an object type by including a method definition in the object constructor function. You could define a function that would format and display the properties of the previously-defined Car objects; for example,

+ +
function displayCar() {
+  var result = 'A Beautiful ' + this.year + ' ' + this.make
+    + ' ' + this.model;
+  pretty_print(result);
+}
+
+ +

where pretty_print is a function to display a horizontal rule and a string. Notice the use of this to refer to the object to which the method belongs.

+ +

You can make this function a method of Car by adding the statement

+ +
this.displayCar = displayCar;
+
+ +

to the object definition. So, the full definition of Car would now look like

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+  this.displayCar = displayCar;
+}
+
+ +

Then you can call the displayCar method for each of the objects as follows:

+ +
car1.displayCar();
+car2.displayCar();
+
+ +

Using this for object references

+ +

JavaScript has a special keyword, this, that you can use within a method to refer to the current object. For example, suppose you have a function called validate that validates an object's value property, given the object and the high and low values:

+ +
function validate(obj, lowval, hival) {
+  if ((obj.value < lowval) || (obj.value > hival)) {
+    alert('Invalid Value!');
+  }
+}
+
+ +

Then, you could call validate in each form element's onchange event handler, using this to pass it the element, as in the following example:

+ +
<input type="text" name="age" size="3"
+  onChange="validate(this, 18, 99)">
+
+ +

In general, this refers to the calling object in a method.

+ +

When combined with the form property, this can refer to the current object's parent form. In the following example, the form myForm contains a Text object and a button. When the user clicks the button, the value of the Text object is set to the form's name. The button's onclick event handler uses this.form to refer to the parent form, myForm.

+ +
<form name="myForm">
+<p><label>Form name:<input type="text" name="text1" value="Beluga"></label>
+<p><input name="button1" type="button" value="Show Form Name"
+     onclick="this.form.text1.value = this.form.name">
+</p>
+</form>
+ +

Defining getters and setters

+ +

A getter is a method that gets the value of a specific property. A setter is a method that sets the value of a specific property. You can define getters and setters on any predefined core object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

+ +

The following illustrates how getters and setters could work for a user-defined object o.

+ +
var o = {
+  a: 7,
+  get b() {
+    return this.a + 1;
+  },
+  set c(x) {
+    this.a = x / 2;
+  }
+};
+
+console.log(o.a); // 7
+console.log(o.b); // 8
+o.c = 50;
+console.log(o.a); // 25
+
+ +

The o object's properties are:

+ + + +

Please note that function names of getters and setters defined in an object literal using "[gs]et property()" (as opposed to __define[GS]etter__ ) are not the names of the getters themselves, even though the [gs]et propertyName(){ } syntax may mislead you to think otherwise. To name a function in a getter or setter using the "[gs]et property()" syntax, define an explicitly named function programmatically using Object.defineProperty (or the Object.prototype.__defineGetter__ legacy fallback).

+ +

The following code illustrates how getters and setters can extend the {{jsxref("Date")}} prototype to add a year property to all instances of the predefined Date class. It uses the Date class's existing getFullYear and setFullYear methods to support the year property's getter and setter.

+ +

These statements define a getter and setter for the year property:

+ +
var d = Date.prototype;
+Object.defineProperty(d, 'year', {
+  get: function() { return this.getFullYear(); },
+  set: function(y) { this.setFullYear(y); }
+});
+
+ +

These statements use the getter and setter in a Date object:

+ +
var now = new Date();
+console.log(now.year); // 2000
+now.year = 2001; // 987617605170
+console.log(now);
+// Wed Apr 18 11:13:25 GMT-0700 (Pacific Daylight Time) 2001
+
+ +

In principle, getters and setters can be either

+ + + +

When defining getters and setters using object initializers all you need to do is to prefix a getter method with get and a setter method with set. Of course, the getter method must not expect a parameter, while the setter method expects exactly one parameter (the new value to set). For instance:

+ +
var o = {
+  a: 7,
+  get b() { return this.a + 1; },
+  set c(x) { this.a = x / 2; }
+};
+
+ +

Getters and setters can also be added to an object at any time after creation using the Object.defineProperties method. This method's first parameter is the object on which you want to define the getter or setter. The second parameter is an object whose property names are the getter or setter names, and whose property values are objects for defining the getter or setter functions. Here's an example that defines the same getter and setter used in the previous example:

+ +
var o = { a: 0 };
+
+Object.defineProperties(o, {
+    'b': { get: function() { return this.a + 1; } },
+    'c': { set: function(x) { this.a = x / 2; } }
+});
+
+o.c = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property
+console.log(o.b); // Runs the getter, which yields a + 1 or 6
+
+ +

Which of the two forms to choose depends on your programming style and task at hand. If you already go for the object initializer when defining a prototype you will probably most of the time choose the first form. This form is more compact and natural. However, if you need to add getters and setters later — because you did not write the prototype or particular object — then the second form is the only possible form. The second form probably best represents the dynamic nature of JavaScript — but it can make the code hard to read and understand.

+ +

Deleting properties

+ +

You can remove a non-inherited property by using the delete operator. The following code shows how to remove a property.

+ +
// Creates a new object, myobj, with two properties, a and b.
+var myobj = new Object;
+myobj.a = 5;
+myobj.b = 12;
+
+// Removes the a property, leaving myobj with only the b property.
+delete myobj.a;
+console.log ('a' in myobj); // yields "false"
+
+ +

You can also use delete to delete a global variable if the var keyword was not used to declare the variable:

+ +
g = 17;
+delete g;
+
+ +

Comparing Objects

+ +

In JavaScript objects are a reference type. Two distinct objects are never equal, even if they have the same properties. Only comparing the same object reference with itself yields true.

+ +
// Two variables, two distinct objects with the same properties
+var fruit = {name: 'apple'};
+var fruitbear = {name: 'apple'};
+
+fruit == fruitbear; // return false
+fruit === fruitbear; // return false
+ +
// Two variables, a single object
+var fruit = {name: 'apple'};
+var fruitbear = fruit;  // assign fruit object reference to fruitbear
+
+// here fruit and fruitbear are pointing to same object
+fruit == fruitbear; // return true
+fruit === fruitbear; // return true
+
+ +
fruit.name = 'grape';
+console.log(fruitbear);    // yields { name: "grape" } instead of { name: "apple" }
+
+ +

For more information about comparison operators, see Comparison operators.

+ +

See also

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Feinheiten_des_Objektmodells")}}

diff --git a/files/de/web/javascript/guide/modules/index.html b/files/de/web/javascript/guide/modules/index.html new file mode 100644 index 0000000000..25dfa9cadb --- /dev/null +++ b/files/de/web/javascript/guide/modules/index.html @@ -0,0 +1,446 @@ +--- +title: JavaScript modules +slug: Web/JavaScript/Guide/Modules +translation_of: Web/JavaScript/Guide/Modules +--- +
+

Ein Hintergrund zu den Modulen

+ +


+ JavaScript-Programme haben ziemlich klein angefangen - in der Anfangszeit wurde es hauptsächlich für isolierte Skripting-Aufgaben verwendet, um Ihren Webseiten bei Bedarf ein wenig Interaktivität zu verleihen, so dass große Skripte im Allgemeinen nicht erforderlich waren. Spätestens nach ein paar Jahren haben wir nun komplette Anwendungen, die in Browsern mit viel JavaScript ausgeführt werden, sowie JavaScript, das auch in anderen Kontexten verwendet wird (z.B. Node.js).

+ +

Daher war es in den letzten Jahren sinnvoll, darüber nachzudenken, Mechanismen zur Aufteilung von JavaScript-Programmen in separate Module bereitzustellen, die bei Bedarf importiert werden können. Node.js besitzt diese Fähigkeit schon seit langem, und es gibt eine Reihe von JavaScript-Bibliotheken und Frameworks, die die Verwendung von Modulen ermöglichen (z.B. andere CommonJS- und AMD-basierte Modulsysteme wie RequireJS und seit kurzem auch Webpack und Babel).

+ +

Die gute Nachricht ist, dass moderne Browser begonnen haben, die Modulfunktionalität nativ zu unterstützen, und genau darum geht es in diesem Artikel. Das kann nur eine gute Sache sein - Browser können das Laden von Modulen optimieren und damit effizienter machen, als wenn man eine Bibliothek verwenden müsste und all diese zusätzlichen clientseitigen Verarbeitungen und zusätzlichen Roundtrips durchführen müsste.

+ +

Übersetzt mit www.DeepL.com/Translator (kostenlose Version)

+
+ +

Browser support

+ +

Die Verwendung von nativen JavaScript-Modulen ist abhängig von den Import- und Export-Anweisungen {{JSxRef("Statements/import", "import")}} und{{JSxRef("Statements/export", "export")}} , deren Browserkompatibilität wie folgt ist (die Zahlen in den grünen Kästen sind wahrscheinlich die Release-Version der jeweiligen Plattform, die die Funktion unterstützt):

+ +

import

+ +

{{Compat("javascript.statements.import")}}

+ +

export

+ +

{{Compat("javascript.statements.export")}}

+ +

Introducing an example

+ +

To demonstrate usage of modules, we've created a simple set of examples that you can find on GitHub. These examples demonstrate a simple set of modules that create a <canvas> element on a webpage, and then draw (and report information about) different shapes on the canvas.

+ +

These are fairly trivial, but have been kept deliberately simple to demonstrate modules clearly.

+ +
+

Note: If you want to download the examples and run them locally, you'll need to run them through a local web server.

+
+ +

Basic example structure

+ +

In our first example (see basic-modules) we have a file structure as follows:

+ +
index.html
+main.js
+modules/
+    canvas.js
+    square.js
+ +
+

Note: All of the examples in this guide have basically the same structure; the above should start getting pretty familiar.

+
+ +

The modules directory's two modules are described below:

+ + + +

Aside — .mjs versus .js

+ +

Throughout this article, we've used .js extensions for our module files, but in other resources you may see the .mjs extension used instead. V8's documentation recommends this, for example. The reasons given are:

+ + + +

However, we decided to keep to using .js, at least for the moment. To get modules to work correctly in a browser, you need to make sure that your server is serving them with a Content-Type header that contains a JavaScript MIME type such as text/javascript. If you don't, you'll get a strict MIME type checking error along the lines of "The server responded with a non-JavaScript MIME type" and the browser won't run your JavaScript. Most servers already set the correct type for .js files, but not yet for .mjs files. Servers that already serve .mjs files correctly include GitHub Pages and http-server for Node.js.

+ +

This is OK if you are using such an environment already, or if you aren't but you know what you are doing and have access (i.e. you can configure your server to set the correct Content-Type for .mjs files). It could however cause confusion if you don't control the server you are serving files from, or are publishing files for public use, as we are here.

+ +

For learning and portability purposes, we decided to keep to .js.

+ +

If you really value the clarity of using .mjs for modules versus using .js for "normal" JavaScript files, but don't want to run into the problem described above, you could always use .mjs during development and convert them to .js during your build step.

+ +

It is also worth noting that:

+ + + +

Exporting module features

+ +

The first thing you do to get access to module features is export them. This is done using the {{JSxRef("Statements/export", "export")}} statement.

+ +

The easiest way to use it is to place it in front of any items you want exported out of the module, for example:

+ +
export const name = 'square';
+
+export function draw(ctx, length, x, y, color) {
+  ctx.fillStyle = color;
+  ctx.fillRect(x, y, length, length);
+
+  return {
+    length: length,
+    x: x,
+    y: y,
+    color: color
+  };
+}
+ +

You can export functions, var, let, const, and — as we'll see later — classes. They need to be top-level items; you can't use export inside a function, for example.

+ +

A more convenient way of exporting all the items you want to export is to use a single export statement at the end of your module file, followed by a comma-separated list of the features you want to export wrapped in curly braces. For example:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

Importing features into your script

+ +

Once you've exported some features out of your module, you need to import them into your script to be able to use them. The simplest way to do this is as follows:

+ +
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
+ +

You use the {{JSxRef("Statements/import", "import")}} statement, followed by a comma-separated list of the features you want to import wrapped in curly braces, followed by the keyword from, followed by the path to the module file — a path relative to the site root, which for our basic-modules example would be /js-examples/modules/basic-modules.

+ +

However, we've written the path a bit differently — we are using the dot (.) syntax to mean "the current location", followed by the path beyond that to the file we are trying to find. This is much better than writing out the entire relative path each time, as it is shorter, and it makes the URL portable — the example will still work if you move it to a different location in the site hierarchy.

+ +

So for example:

+ +
/js-examples/modules/basic-modules/modules/square.js
+ +

becomes

+ +
./modules/square.js
+ +

You can see such lines in action in main.js.

+ +
+

Note: In some module systems, you can omit the file extension and the dot (e.g. '/modules/square'). This doesn't work in native JavaScript modules.

+
+ +

Once you've imported the features into your script, you can use them just like they were defined inside the same file. The following is found in main.js, below the import lines:

+ +
let myCanvas = create('myCanvas', document.body, 480, 320);
+let reportList = createReportList(myCanvas.id);
+
+let square1 = draw(myCanvas.ctx, 50, 50, 100, 'blue');
+reportArea(square1.length, reportList);
+reportPerimeter(square1.length, reportList);
+
+ +

Applying the module to your HTML

+ +

Now we just need to apply the main.js module to our HTML page. This is very similar to how we apply a regular script to a page, with a few notable differences.

+ +

First of all, you need to include type="module" in the <script> element, to declare this script as a module:

+ +
<script type="module" src="main.js"></script>
+ +

The script into which you import the module features basically acts as the top-level module. If you omit it, Firefox for example gives you an error of "SyntaxError: import declarations may only appear at top level of a module".

+ +

You can only use import and export statements inside modules; not regular scripts.

+ +
+

Note: You can also import modules into internal scripts, as long as you include type="module", for example <script type="module"> //include script here </script>.

+
+ +

Other differences between modules and standard scripts

+ + + +

Default exports versus named exports

+ +

The functionality we've exported so far has been comprised of named exports — each item (be it a function, const, etc.) has been referred to by its name upon export, and that name has been used to refer to it on import as well.

+ +

There is also a type of export called the default export — this is designed to make it easy to have a default function provided by a module, and also helps JavaScript modules to interoperate with existing CommonJS and AMD module systems (as explained nicely in ES6 In Depth: Modules by Jason Orendorff; search for "Default exports").

+ +

Let's look at an example as we explain how it works. In our basic-modules square.js you can find a function called randomSquare() that creates a square with a random color, size, and position. We want to export this as our default, so at the bottom of the file we write this:

+ +
export default randomSquare;
+ +

Note the lack of curly braces.

+ +

We could instead prepend export default onto the function and define it as an anonymous function, like this:

+ +
export default function(ctx) {
+  ...
+}
+ +

Over in our main.js file, we import the default function using this line:

+ +
import randomSquare from './modules/square.js';
+ +

Again, note the lack of curly braces. This is because there is only one default export allowed per module, and we know that randomSquare is it. The above line is basically shorthand for:

+ +
import {default as randomSquare} from './modules/square.js';
+ +
+

Note: The as syntax for renaming exported items is explained below in the Renaming imports and exports section.

+
+ +

Avoiding naming conflicts

+ +

So far, our canvas shape drawing modules seem to be working OK. But what happens if we try to add a module that deals with drawing another shape, like a circle or triangle? These shapes would probably have associated functions like draw(), reportArea(), etc. too; if we tried to import different functions of the same name into the same top-level module file, we'd end up with conflicts and errors.

+ +

Fortunately there are a number of ways to get around this. We'll look at these in the following sections.

+ +

Renaming imports and exports

+ +

Inside your import and export statement's curly braces, you can use the keyword as along with a new feature name, to change the identifying name you will use for a feature inside the top-level module.

+ +

So for example, both of the following would do the same job, albeit in a slightly different way:

+ +
// inside module.js
+export {
+  function1 as newFunctionName,
+  function2 as anotherNewFunctionName
+};
+
+// inside main.js
+import { newFunctionName, anotherNewFunctionName } from './modules/module.js';
+ +
// inside module.js
+export { function1, function2 };
+
+// inside main.js
+import { function1 as newFunctionName,
+         function2 as anotherNewFunctionName } from './modules/module.js';
+ +

Let's look at a real example. In our renaming directory you'll see the same module system as in the previous example, except that we've added circle.js and triangle.js modules to draw and report on circles and triangles.

+ +

Inside each of these modules, we've got features with the same names being exported, and therefore each has the same export statement at the bottom:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

When importing these into main.js, if we tried to use

+ +
import { name, draw, reportArea, reportPerimeter } from './modules/square.js';
+import { name, draw, reportArea, reportPerimeter } from './modules/circle.js';
+import { name, draw, reportArea, reportPerimeter } from './modules/triangle.js';
+ +

The browser would throw an error such as "SyntaxError: redeclaration of import name" (Firefox).

+ +

Instead we need to rename the imports so that they are unique:

+ +
import { name as squareName,
+         draw as drawSquare,
+         reportArea as reportSquareArea,
+         reportPerimeter as reportSquarePerimeter } from './modules/square.js';
+
+import { name as circleName,
+         draw as drawCircle,
+         reportArea as reportCircleArea,
+         reportPerimeter as reportCirclePerimeter } from './modules/circle.js';
+
+import { name as triangleName,
+        draw as drawTriangle,
+        reportArea as reportTriangleArea,
+        reportPerimeter as reportTrianglePerimeter } from './modules/triangle.js';
+ +

Note that you could solve the problem in the module files instead, e.g.

+ +
// in square.js
+export { name as squareName,
+         draw as drawSquare,
+         reportArea as reportSquareArea,
+         reportPerimeter as reportSquarePerimeter };
+ +
// in main.js
+import { squareName, drawSquare, reportSquareArea, reportSquarePerimeter } from './modules/square.js';
+ +

And it would work just the same. What style you use is up to you, however it arguably makes more sense to leave your module code alone, and make the changes in the imports. This especially makes sense when you are importing from third party modules that you don't have any control over.

+ +

Creating a module object

+ +

The above method works OK, but it's a little messy and longwinded. An even better solution is to import each module's features inside a module object. The following syntax form does that:

+ +
import * as Module from './modules/module.js';
+ +

This grabs all the exports available inside module.js, and makes them available as members of an object Module, effectively giving it its own namespace. So for example:

+ +
Module.function1()
+Module.function2()
+etc.
+ +

Again, let's look at a real example. If you go to our module-objects directory, you'll see the same example again, but rewritten to take advantage of this new syntax. In the modules, the exports are all in the following simple form:

+ +
export { name, draw, reportArea, reportPerimeter };
+ +

The imports on the other hand look like this:

+ +
import * as Canvas from './modules/canvas.js';
+
+import * as Square from './modules/square.js';
+import * as Circle from './modules/circle.js';
+import * as Triangle from './modules/triangle.js';
+ +

In each case, you can now access the module's imports underneath the specified object name, for example:

+ +
let square1 = Square.draw(myCanvas.ctx, 50, 50, 100, 'blue');
+Square.reportArea(square1.length, reportList);
+Square.reportPerimeter(square1.length, reportList);
+ +

So you can now write the code just the same as before (as long as you include the object names where needed), and the imports are much neater.

+ +

Modules and classes

+ +

As we hinted at earlier, you can also export and import classes; this is another option for avoiding conflicts in your code, and is especially useful if you've already got your module code written in an object-oriented style.

+ +

You can see an example of our shape drawing module rewritten with ES classes in our classes directory. As an example, the square.js file now contains all its functionality in a single class:

+ +
class Square {
+  constructor(ctx, listId, length, x, y, color) {
+    ...
+  }
+
+  draw() {
+    ...
+  }
+
+  ...
+}
+ +

which we then export:

+ +
export { Square };
+ +

Over in main.js, we import it like this:

+ +
import { Square } from './modules/square.js';
+ +

And then use the class to draw our square:

+ +
let square1 = new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+square1.draw();
+square1.reportArea();
+square1.reportPerimeter();
+ +

Aggregating modules

+ +

There will be times where you'll want to aggregate modules together. You might have multiple levels of dependencies, where you want to simplify things, combining several submodules into one parent module. This is possible using export syntax of the following forms in the parent module:

+ +
export * from 'x.js'
+export { name } from 'x.js'
+ +

For an example, see our module-aggregation directory. In this example (based on our earlier classes example) we've got an extra module called shapes.js, which aggregates all the functionality from circle.js, square.js, and triangle.js together. We've also moved our submodules inside a subdirectory inside the modules directory called shapes. So the module structure in this example is:

+ +
modules/
+  canvas.js
+  shapes.js
+  shapes/
+    circle.js
+    square.js
+    triangle.js
+ +

In each of the submodules, the export is of the same form, e.g.

+ +
export { Square };
+ +

Next up comes the aggregation part. Inside shapes.js, we include the following lines:

+ +
export { Square } from './shapes/square.js';
+export { Triangle } from './shapes/triangle.js';
+export { Circle } from './shapes/circle.js';
+ +

These grab the exports from the individual submodules and effectively make them available from the shapes.js module.

+ +
+

Note: The exports referenced in shapes.js basically get redirected through the file and don't really exist there, so you won't be able to write any useful related code inside the same file.

+
+ +

So now in the main.js file, we can get access to all three module classes by replacing

+ +
import { Square } from './modules/square.js';
+import { Circle } from './modules/circle.js';
+import { Triangle } from './modules/triangle.js';
+ +

with the following single line:

+ +
import { Square, Circle, Triangle } from './modules/shapes.js';
+ +

Dynamic module loading

+ +

The newest part of the JavaScript modules functionality to be available in browsers is dynamic module loading. This allows you to dynamically load modules only when they are needed, rather than having to load everything up front. This has some obvious performance advantages; let's read on and see how it works.

+ +

This new functionality allows you to call {{JSxRef("Statements/import", "import()", "#Dynamic_Imports")}} as a function, passing it the path to the module as a parameter. It returns a {{JSxRef("Promise")}}, which fulfills with a module object (see Creating a module object) giving you access to that object's exports, e.g.

+ +
import('./modules/myModule.js')
+  .then((module) => {
+    // Do something with the module.
+  });
+ +

Let's look at an example. In the dynamic-module-imports directory we've got another example based on our classes example. This time however we are not drawing anything on the canvas when the example loads. Instead, we include three buttons — "Circle", "Square", and "Triangle" — that, when pressed, dynamically load the required module and then use it to draw the associated shape.

+ +

In this example we've only made changes to our index.html and main.js files — the module exports remain the same as before.

+ +

Over in main.js we've grabbed a reference to each button using a Document.querySelector() call, for example:

+ +
let squareBtn = document.querySelector('.square');
+ +

We then attach an event listener to each button so that when pressed, the relevant module is dynamically loaded and used to draw the shape:

+ +
squareBtn.addEventListener('click', () => {
+  import('./modules/square.js').then((Module) => {
+    let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
+    square1.draw();
+    square1.reportArea();
+    square1.reportPerimeter();
+  })
+});
+ +

Note that, because the promise fulfillment returns a module object, the class is then made a subfeature of the object, hence we now need to access the constructor with Module. prepended to it, e.g. Module.Square( ... ).

+ +

Troubleshooting

+ +

Here are a few tips that may help you if you are having trouble getting your modules to work. Feel free to add to the list if you discover more!

+ + + +

See also

+ + + +

{{Previous("Web/JavaScript/Guide/Meta_programming")}}

diff --git a/files/de/web/javascript/guide/numbers_and_dates/index.html b/files/de/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..b38881bb07 --- /dev/null +++ b/files/de/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,378 @@ +--- +title: Numbers and dates +slug: Web/JavaScript/Guide/Numbers_and_dates +tags: + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Ausdruecke_und_Operatoren", "Web/JavaScript/Guide/Text_formatting")}}
+ +

Dieses Kapitel ist eine Einleitung in die Nutzung von Nummern und Daten in JavaScript.

+ +

Nummern

+ +

In JavaScript sind alle Nummern als double-precision 64-Bit Binärformat IEEE 754 umgesetzt (z.b. eine Zahl zwischen -(253 -1) und 253 -1). Es gibt keinen extra Datentypen für ganze Zahlen (z. B. Integer in anderen Programmiersprachen). Neben der Repräsentation von Gleitkommazahlen hat der Nummern Typ noch drei symbolische Werte: +{{jsxref("Infinity")}}, -{{jsxref("Infinity")}}, und {{jsxref("NaN")}} (not-a-number; keine Nummer). Siehe auch in das Kapitel JavaScript Datentypen und Strukturen für den Umgang mit anderen primitiven Typen in JavaScript.

+ +

Es gibt vier verschiedene Nummernliterale: Dezimal-, Binär-, Oktal- und Hexadezimalzahlen.

+ +

Dezimalzahlen

+ +
1234567890
+42
+
+// Vorsichtig mit führenden Nullen in der Darstellung:
+
+0888 // wird zu 888 Dezimal
+0777 // wird im non-strict Modus zu 511 in Dezimal
+
+ +

Zu beachten ist, dass das Dezimalliteral mit einer 0 beginnen kann, jedoch wird die Zahl als Oktalzahl interpretiert, wenn die nächste Zahl nach der 0 kleiner als 8 ist.

+ +

Binärzahlen

+ +

Die Syntax von Binärzahlen schreibt vor, dass die Zahl mit einer 0 gefolgt von einem "B" (0b oder 0B) beginnen muss. Wenn die Ziffern nach dem 0b nicht 0 oder 1 sind, wird der folgenden SyntaxError erzeugt: "Missing binary digits after 0b".

+ +
var FLT_SIGNBIT  = 0b10000000000000000000000000000000; // 2147483648
+var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
+var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607
+ +

Oktalzahlen

+ +

Die Syntax von Oktalzahlen schreibt vor, dass die Nummern mit einer 0 beginnen. Dahinter sind Ziffern mit den Werten 0 bis 7 möglich. Wenn die Ziffern größer als 7 sind, wird die Zahl als Dezimalzahl interpretiert.

+ +
var n = 0755; // 493
+var m = 0644; // 420
+
+ +

Der Strict mode in ECMAScript 5 verbietet Oktalzahlen. Die Syntax der Oktalzahlen ist in ECMAScript 5 nicht vorhanden, jedoch wird es von allen Browser, durch eine führende 0, unterstützt: 0644 === 420 und "\045" === "%". In ECMAScript 2015 sind Oktalzahlen mit dem Präfix 0o unterstützt:

+ +
var a = 0o10; // ES2015: 8
+
+ +

Hexadezimalzahlen

+ +

Hexadezimalzahlen können geschrieben werden, indem der Präfix 0x oder 0X genutzt wird. Wenn die Ziffern nach 0x nicht eines der Zeichen 0123456789ABCDEF entspricht, wird folgender SyntaxError  erzeugt: "Identifier starts immediately after numeric literal".

+ +
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
+0x123456789ABCDEF   // 81985529216486900
+0XA                 // 10
+
+ +

Potenzierung

+ +
1E3   // 1000
+2e6   // 2000000
+0.1e2 // 10
+ +

Number Objekt

+ +

Das vordefinierte {{jsxref("Number")}} Objekt enthält Eigenschaften für nummerische Konstanten, wie zum Beispiel Maximalwerte, not-a-number (keine Nummer) und Unendlich. Man kann die Werte dieser Eigenschaften nicht ändern. Die Eigenschaften werden folgendermaßen eingesetzt:

+ +
var biggestNum = Number.MAX_VALUE;
+var smallestNum = Number.MIN_VALUE;
+var infiniteNum = Number.POSITIVE_INFINITY;
+var negInfiniteNum = Number.NEGATIVE_INFINITY;
+var notANum = Number.NaN;
+
+ +

Man verweist immer auf die Eigenschaften des vordefinierten Number Objekt (wie oben gezeigt) und nicht auf die Eigenschaft eines selbst erstellten Number Objektes.

+ +

Die folgende Tabelle fasst du Eigenschaften des Number Objektes zusammen:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Eigenschaften von Number
EigenschaftBeschreibung
{{jsxref("Number.MAX_VALUE")}}Die größte repräsentierbare Zahl
{{jsxref("Number.MIN_VALUE")}}Die kleinste repräsentierbare Zahl
{{jsxref("Number.NaN")}}Spezieller Wert für "keine Zahl" ("not a number")
{{jsxref("Number.NEGATIVE_INFINITY")}}Spezieller Wert für negativ Unendlich; wird bei einem Overflow zurückgegeben.
{{jsxref("Number.POSITIVE_INFINITY")}}Spezieller Wert für positiv Unendlich; wird bei einem Overflow zurückgegeben.
{{jsxref("Number.EPSILON")}}Der Unterschied zwischen eins und der kleinsten Zahl größer als eins, die als {{jsxref("Number")}} repräsentiert werden kann.
{{jsxref("Number.MIN_SAFE_INTEGER")}}Kleinste sichere ganze Zahl in JavaScript.
{{jsxref("Number.MAX_SAFE_INTEGER")}}Größte sichere ganze Zahl in JavaScript.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Methoden von Number
MethodeBeschreibung
{{jsxref("Number.parseFloat()")}}Liest eine String-Argument ein und gibt eine Floating-Point Zahl zurück.
+ Macht das gleiche wie die globale {{jsxref("parseFloat", "parseFloat()")}} Funktion.
{{jsxref("Number.parseInt()")}}Liest eine String-Argument ein und gibt eine ganze Zahl in der spezifizierten Basis zurück.
+ Macht das gleiche wie die globale {{jsxref("parseInt", "parseInt()")}} Funktion.
{{jsxref("Number.isFinite()")}}Erkennt, ob ein übergebener Wert eine endliche Zahl ist.
{{jsxref("Number.isInteger()")}}Erkennt, ob ein übergebener Wert eine ganze Zahl ist.
{{jsxref("Number.isNaN()")}}Erkennt, ob ein übergebener Wert {{jsxref("Global_Objects/NaN", "NaN")}} ist. Diese Funktion ist eine robustere Version der globalen {{jsxref("Global_Objects/isNaN", "isNaN()")}} Funktion
{{jsxref("Number.isSafeInteger()")}}Erkennt, ob ein übergebener Wert eine sichere ganze Zahl ist.
+ +

Der Number Prototyp enthält Methoden zum Zurückgeben von Informationen eines Number Objekts in verschiedenen Formaten. Die folgende Tabelle fasst die Methoden von Number.prototype zusammen:

+ + + + + + + + + + + + + + + + + + + + + + + +
Methoden von Number.prototype
MethodeBeschreibung
{{jsxref("Number.toExponential", "toExponential()")}}Gibt eine String-Repräsentation der Zahl in Exponential-Notation zurück.
{{jsxref("Number.toFixed", "toFixed()")}}Gibt eine String-Repräsentation der Zahl in Festkomma-Notation zurück.
{{jsxref("Number.toPrecision", "toPrecision()")}}Gibt eine String-Repräsentation der Zahl in einer spezifizierten Präzision in der Festkomma-Notation zurück.
+ +

Math Objekt

+ +

Das eingebaute {{jsxref("Math")}} Objekt hat Eigenschaften und Methoden für mathematische Konstanten und Funktionen. Zum Beispiel enthält die Eigenschaft PI des Math Objektes den Wert von Pi (3,141...), welche wie folgt in einer Anwendung eingesetzt wird:

+ +
Math.PI
+
+ +

Genauso sind mathematische Standardfunktionen Methoden von Math. Dabei sind trigonometrische, logarithmische, exponentielle und ander Funktionen enthalten. Zum Beispiel wird eine trigonometrische Funktion wie folgt eingesetzt:

+ +
Math.sin(1.56)
+
+ +

Alle trigonometrischen Funktionen von Math erwarten Argumente im Radiantenmaß.

+ +

Die folgende Tabelle fasst die Methoden des Math Objektes zusammen:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Methoden von Math
MethodeBeschreibung
{{jsxref("Math.abs", "abs()")}}Absoluter Wert.
{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}}Trigonometrische Standardfunktionen; Argumente im Radiantenmaß.
{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}}Inverse trigonometrische Standardfunktionen; Rückgabewert im Radiantenmaß.
{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}}Hyperbolische trigonometrische Standardfunktionen; Rückgabewert im Radiantenmaß.
{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}}Inverse hyperbolische trigonometrische Standardfunktionen; Rückgabewert im Radiantenmaß.
+

{{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}}

+
Exponential- und Logarithmus-Funktionen.
{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}}Gibt die größte/kleinste ganze Zahl kleiner/größer oder gleich dem Argument zurück.
{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}}Gibt den kleinsten oder den größten Wert aus einer mit Komma getrennten Liste von Zahlen.
{{jsxref("Math.random", "random()")}}Gibt eine Zufallszahl zwischen 0 und 1 zurück.
{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}},Rundungs- und Abschnittsfunktionen.
{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}}Quadratwurzel, kubische Wurzel, Quadratwurzel von der Summe von Quadrierten Argumenten.
{{jsxref("Math.sign", "sign()")}}Das Vorzeichen einer Zahl, welches Angibt, ob eine Zahl positiv, negativ oder null ist.
{{jsxref("Math.clz32", "clz32()")}},
+ {{jsxref("Math.imul", "imul()")}}
Anzahl der führenden 0-Bits in der 32-Bit Binärrepräsentation.
+ Das Resultat der C-Ähnlichen 32-Bit Multiplikation von 2 Argumenten.
+ +

Im Gegensatz zu vielen Anderen Objekten, erzeigt man nie selber ein neues Math Objekt. Man benutzt immer das globale Objekt.

+ +

Date Objekt

+ +

JavaScript hat keinen Datums-Datentypen. Allerdings kann das {{jsxref("Date")}} Objekt und seine Methoden genutzt werden, um mit Daten und Zeiten in einer Applikation zu arbeiten. Das Date-Objekt hat sehr viele Methoden für das Einstellen, Abfragen und Manipulieren von Daten. Es hat keine Eigenschaften.

+ +

JavaScript verarbeitet Daten ähnlich wie es in Java gemacht wird. In beiden Sprachen sind viele Methoden gleich und beide Sprachen speichern das Datum als Unix Zeitstempel, also die Anzahl der Millisekunden seit dem 1. Januar 1970 00:00:00, ab.

+ +

Der Wertebereich eines Date Objektes ist zwischen -100.000.000 und 100.000.000 Tagen relativ zum 1. Januar 1970 UTC.

+ +

Das erstellen eines Date Objektes:

+ +
var dateObjectName = new Date([parameters]);
+
+ +

Dabei ist dateObjectName der Name der Variablen, in der das erstellte Date Objekt gespeichert wird.

+ +

Unter parameters können folgenden Werte eingesetzt werden:

+ + + +

Methoden des Date Objektes

+ +

Das Methoden des Date Objektes für die Behandlung von Daten und Zeiten werden in folgende Kategorien eingeteilt:

+ + + +

Mit den "get"- und "set"-Methoden können Sekunden, Minuten, Stunden, Tag des Monats, Wochentag, Monat und Jahr separat eingestellt und abgefragt werden. Es gibt eine getDay-Methode, welche den Wochentag zurückgibt, es gibt aber keine vergleichbare setDay-Methode, weil der Wochentag automatisch eingestellt wird. Diese Methoden benutzen ganze Zahlen um folgende Werte darzustellen:

+ + + +

Angenommen, man erstellt folgendes Datum:

+ +
var Xmas95 = new Date("December 25, 1995");
+
+ +

Dann gibt Xmas95.getMonth() 11 zurück und Xmas95.getFullYear() gibt 1995 zurück.

+ +

Die getTime und setTime Methoden sind nützlich für das Vergleichen von Daten. Die getTime Methode gibt die Anzahl der Millisekunden seit dem 1. Januar 1970 00:00:00 eines Date-Objektes zurück.

+ +

Der folgende Quelltext zeigt, wie die Anzahl der vergangenen Tage des aktuellen Jahres ermittelt werden kann:

+ +
var today = new Date();
+var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Stellt den Tag und den Monat ein
+endYear.setFullYear(today.getFullYear()); // Stellt das Jahr auf das aktuelle Jahr
+var msPerDay = 24 * 60 * 60 * 1000; // Anzahl der Millisekunden pro Tag
+var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay;
+var daysLeft = Math.round(daysLeft); //gibt die vergangenen Tage des aktuellen Jahres zurück
+
+ +

Diese Beispiel erstellt ein Date-Objekt namens today, welches das aktuelle Datum und die aktuelle Zeit enthält. Danach wird ein das Date-Objekt endYear erstellt und das Jahr wird auf das aktuelle Jahr eingestellt. Zum Schluss wird, mithilfe der Millisekunden pro Tag, die Anzahl der Tage zwischen today und endYear berechnet. Dafür wird die getTime Methode eingesetzt und es wird auf eine ganze Zahl von Tagen gerundet.

+ +

Die parse Methode ist nützlich, um ein Date-Objekt aus einem String zu erstellen. Zum Beispiel verwendet der folgende Quelltext parse und setTime um das IPOdate einzustellen:

+ +
var IPOdate = new Date();
+IPOdate.setTime(Date.parse("Aug 9, 1995"));
+
+ +

Beispiel

+ +

Im folgenden Beispiel, gibt die JSClock() Funktion die Zeit in dem Format einer digitalen Uhr zurück.

+ +
function JSClock() {
+  var time = new Date();
+  var hour = time.getHours();
+  var minute = time.getMinutes();
+  var second = time.getSeconds();
+  var temp = "" + ((hour > 12) ? hour - 12 : hour);
+  if (hour == 0)
+    temp = "12";
+  temp += ((minute < 10) ? ":0" : ":") + minute;
+  temp += ((second < 10) ? ":0" : ":") + second;
+  temp += (hour >= 12) ? " P.M." : " A.M.";
+  return temp;
+}
+
+ +

Die JSClock Funktion erstellt als erstes ein neues Date Objekt mit dem Namen time. Weil dabei keine Argumente angegeben werden, wird time mit dem aktuellen Datum und der aktuellen Zeit erstellt. Danach werden die Methoden getHours, getMinutes, und getSeconds eingesetzt, um den Wert der aktuellen Stunde, Minute und Sekunde in den Variablen  hour, minute, und second zu speichern.

+ +

Die nächsten vier Statements bauen einen String-Wert mit der Zeit zusammen. Das erste Statement erstellt eine Variable temp und weist dieser einen Wert mit einem bedingten Ausdruck zu; wenn hour größer als 12 ist wird hour - 12 zugewiesen, andernfalls nur hour. Wenn hour dann 0 ist, wird hour auf 12 gesetzt.

+ +

Die nächsten Statement hängt einen den minute-Wert an temp heran. Wenn der Wert von minute kleiner als 10 ist, fügt der Bedingte Ausdruck einen String mit einer Null und einem Doppelpunkt an; andernfalls wird nur ein Doppelpunkt angehängt. Danach werden die Sekunden auf die gleiche weise angehängt.

+ +

Zum Schluss fügt ein bedingter Ausdruck "P.M." an temp an, wenn die hour größer oder gleich 12 ist. Andernfalls wird "A.M." an temp angefügt.

+ +

{{PreviousNext("Web/JavaScript/Guide/Ausdruecke_und_Operatoren", "Web/JavaScript/Guide/Text_formatting")}}

diff --git a/files/de/web/javascript/guide/regular_expressions/index.html b/files/de/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..4710e4e352 --- /dev/null +++ b/files/de/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,625 @@ +--- +title: Reguläre Ausdrücke +slug: Web/JavaScript/Guide/Regular_Expressions +tags: + - JavaScript + - ausdrücke + - regex + - reguläre +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Textformatierung", "Web/JavaScript/Guide/Indexed_collections")}}
+ +

Reguläre Ausdrücke sind Muster, die eingesetzt werden, um Text auf bestimmte Zeichenkombinationen zu überprüfen. Auch reguläre Ausdrücke sind Objekte bei JavaScript. Die Muster werden mit den Methoden exec und test von RegExp und den Methoden match, replace, search und split von String verwendet. Dieses Kapitel beschreibt reguläre Ausdrücke in JavaScript.

+ +

Erstellen von regulären Ausdrücken

+ +

Ein regulärer Ausdruck kann auf zwei verschiedene Arten erstellt werden.

+ +

Zum einen kann ein Literal verwendet werden:

+ +
var re = /ab+c/;
+ +

Hierbei findet die Kompilierung des regulären Ausdrucks während der Auswertung des Skripts statt. Wenn der reguläre Ausdruck konstant bleibt, ist diese Vorgehensweise aufgrund der schnelleren Ausführungsgeschwindigkeit empfehlenswert.

+ +

Zum anderen kann wie folgt die Konstruktorfunktion des Objekts RegExp zum Einsatz kommen:

+ +
var re = new RegExp("ab+c");
+ +

Bei der Benutzung der Konstruktorfunktion wird der reguläre Ausdruck während der Laufzeit kompiliert. Sie sollte verwendet werden, wenn man weiß, dass sich das Muster während der Laufzeit ändert oder man das Muster noch nicht kennt und von einer anderen Quelle, wie z. B. der Benutzereingabe, bezieht.

+ +

Schreiben von Mustern für reguläre Ausdrücke

+ +

Ein Muster eines regulären Ausdrucks wird aus einfachen Zeichen, wie z. B. /abc/ oder einer Kombination von einfachen und speziellen Zeichen, wie z. B. /ab*c/ oder /Kapitel (\d+)\.\d*/ erstellt. Das letzte Beispiel enthält Klammern, die zur Speicherung verwendet werden. Die Übereinstimmung im Text, welche auf das eingeklammerte Muster passt, wird hierbei für die spätere Verwendung hinterlegt, wie unter Benutzung von geklammerten Mustern beschrieben.

+ +

Verwendung von einfachen Mustern

+ +

Einfache Muster werden aus Zeichen konstruiert, für die man eine direkte Übereinstimmung finden möchte. Zum Beispiel passt das Muster /abc/ nur dann für eine Zeichenkette, wenn exakt die Zeichen "abc" aufeinanderfolgend in dieser Reihenfolge vorkommen. Solch eine Übereinstimmung kommt z. B. in der Zeichenkette "Hallo, kennst du das abc?" und "Das müssen wir noch abchecken." vor. In beiden Fällen enthält die Zeichenkette die Zeichenfolge "abc". In der Zeichenkette "Stab" gibt es keine Übereinstimmung, weil die Zeichenfolge "abc" darin nicht vorkommt.

+ +

Verwendung von speziellen Zeichen

+ +

Wenn bei der Suche nicht nur nach einer direkten Übereinstimmung, sondern z. B. nach einem oder mehreren aufeinanderfolgenden Vorkommen des Buchstabens "b" oder nach Leerräumen (sowohl Tabulator, Leerzeichen als auch Steuerzeichen) gesucht wird, kommen spezielle Zeichen zum Einsatz. Zum Beispiel stimmt das Muster /ab*c/ mit allen Zeichenkombinationen überein, die ein "a", dann sofort nachfolgend 0 oder mehrere "b" (Das Sternchen bedeutet: 0 oder mehr Vorkommen des vorherigen Zeichens) und anschließend sofort ein "c" enthalten. Demnach wird in der Zeichenfolge "cbbabbbbcdebc" eine Übereinstimmung gefunden, weil das Muster auf die Zeichenfolge "abbbbc" passt.

+ +

Die folgende Tabelle zeigt eine komplette Liste der speziellen Zeichen, die in regulären Ausdrücken verwendet werden, mit einer Beschreibung zu deren Bedeutung.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabelle 4.1 Spezielle Zeichen in regulären Ausdrücken
ZeichenBedeutung
\Eine der folgenden Bedeutungen: +
    +
  • Für Zeichen, die normalerweise buchstäblich interpretiert werden, wird mit der Voranstellung des Rückstrichs dafür gesorgt, dass das Zeichen als speziell und nicht als normales Zeichen interpretiert wird. Zum Beispiel stimmt /b/ mit dem Zeichen "b" überein. Stellt man dem "b" einen Rückstrich voran, also /\b/, wird das Zeichen als spezielles Zeichen - in diesem Fall als Wortgrenze - gedeutet.
  • +
  • Bei Zeichen, die normalerweise sofort als spezielle Zeichen interpretiert werden, bewirkt der Rückstrich genau das Gegenteil, d.h. dem Zeichen wird die spezielle Bedeutung genommen und es wird als einfaches Zeichen interpretiert. Zum Beispiel ist das Zeichen * (Sternchen) ein spezielles Zeichen mit der Bedeutung: 0 oder mehr Vorkommen des vorherigen Zeichens. Der Ausdruck /a*/ steht demnach für 0 oder mehr a's. Um dem Zeichen * (Sternchen) die spezielle Bedeutung zu nehmen, stellt man ihm einen Rückstrich voran, z. B. stimmt /a\*/ mit "a*" überein - der Stern wird nun als einfaches Zeichen interpretiert.
  • +
  • Das Maskieren eines Zeichens durch die Voranstellung eines Rückstrichs wird auch als escapen bezeichnet. Außerdem sollte man sich merken, dass bei Verwendung der new RegExp("pattern")-Notation auch der Rückstrich selbst eine spezielle Bedeutung hat und maskiert werden muss, wenn er als normales Zeichen interpretiert werden soll.
  • +
+
^ +

Das Zirkumflex-Zeichen steht für den Anfang der Eingabe. Wenn das Flag für mehrere Zeilen (multiline flag) gesetzt ist, wird auch eine Übereinstimmung direkt hinter dem Zeichen für einen Zeilenumbruch (\n) gefunden.

+ +

Der Ausdruck /^A/ passt zwar auf das "A" in "Apfel", nicht jedoch auf das "A" in "Ein Apfel", weil das "A" bei dieser Zeichenkette nicht am Anfang steht.

+ +

Achtung: Wenn das Zeichen innerhalb von eckigen Klammern (einer Zeichenauswahl) steht, hat es eine andere Bedeutung (siehe [^xyz] in dieser Tabelle).

+ +

Zum Beispiel stimmt /[^a-zA-Z\s]/ mit der "3" in "Ich habe 3 Schwestern" überein. Die eckigen Klammern kennzeichnen die Zeichenauswahl. Das Zirkumflex innerhalb dieser Klammern negiert die aufgezählten Zeichen: nicht a bis z, nicht A bis Z und keine Leerräume wie das Leerzeichen oder die Steuerzeichen; übrig bleibt allein die "3".

+
$ +

Das Dollarzeichen steht für das Ende der Eingabe. Wenn das Flag für mehrere Zeilen (multiline flag) gesetzt ist, wird auch eine Übereinstimmung direkt hinter dem Zeichen für einen Zeilenumbruch (\n) gefunden.

+ +

Zum Beispiel wird mit /t$/ bei "Butter" keine Übereinstimmung gefunden, jedoch bei "Brot", weil das "t" am Ende steht.

+
* +

Das Sternchen steht für eine beliebige Anzahl des vorangestellten Zeichens, also 0-mal oder öfter. Das Zeichen muss also nicht unbedingt vorkommen, sondern darf auch einfach nicht vorhanden sein. Das Sternchen wird gerne in Kombination mit dem . (Punkt) als Platzhalter für "ein beliebiges Zeichen beliebig oft" verwendet.

+ +

Der Ausdruck /bu*/ passt auf "buuuuu" in "Ein Geist buuuuuht" als auch auf "b"  in "Ein Blauwal blubbert", jedoch nicht auf "Eine Katze kratzt".

+
+ +

Steht für das vorangestellte Zeichen einmal oder öfter und ist äquivalent zu {1,}. Das Zeichen muss für einen Treffer also mindestens einmal vorkommen.

+ +

Zum Beispiel passt /a+/ auf "a" in "Schokolade" und alle a's in "Schokolaaaade".

+
? +

Steht für das vorangestellte Zeichen 0 oder einmal und ist äquivalent zu {0,1}.

+ +

Zum Beispiel passt /e?le?/ sowohl auf "el" in "Engel", als auch auf "le" in "Kapelle" und auch "l" in "Oslo".

+ +

Wenn es sofort hinter einen der Quantoren *, +, ?, oder {} gestellt wird, deaktiviert es die standardmäßige "Gierigkeit" (eine möglichst hohe Anzahl von passende Zeichen einschließend) dieser Quantoren und macht sie "genügsam" (eine möglichst geringe Anzahl von passende Zeichen einschließend).

+ +

Zum Beispiel passt der Ausdruck /\d+/ auf die Zeichenkette "123abc" angewendet auf "123", weil der Quantor + (Pluszeichen) "gierig" ist. Der Ausdruck /\d+?/ steht hingegen nur für "1", weil der Quantor + (Pluszeichen) aufgrund der Beeinflussung durch das hintangestellte ? (Fragezeichen) "genügsam" ist.

+ +

Das Fragezeichen wird auch bei sogenannten lookahead assertions (vorausschauenden Annahmen/Behauptungen) eingesetzt, die in dieser Tabelle unter x(?=y) und x(?!y) beschrieben sind.

+
. +

Der Punkt steht für ein einzelnes beliebiges Zeichen mit Ausnahme des Zeichens für den Zeilenumbruch.

+ +

Zum Beispiel passt /.n/ auf "in" und "än" in der Zeichenkette "nur ein Apfel hängt am Baum", jedoch nicht auf das "n" ganz am Anfang, weil vor dem "n" ein beliebiges Zeichen stehen muss.

+
(x) +

Steht für die Zeichen "x", also die eingeklammerten Zeichen. Außerdem werden die Zeichen gespeichert, die mit dem einklammerten Muster übereinstimmen, damit sie an anderer Stelle wieder eingesetzt werden können. Die Klammern werden auch capturing parentheses (aufnehmende Klammern) genannt.

+ +

Zum Beispiel steht /(foo)/ für "foo" in "foobar" und "foo" wird hinterlegt. Die Zeichen innerhalb der Klammern können durch Array-Elemente wieder eingesetzt werden. Dabei steht [1] für die Zeichen des ersten Klammerpaars, [2] für die Zeichen des zweiten Paars usw.

+
(?:x)Steht für die Zeichen "x", aber die Übereinstimmung wird nicht hinterlegt. Diese Klammern werden auch als non-capturing parentheses bezeichnet. Die übereinstimmenden Zeichen können nicht wieder eingesetzt werden und die Array-Elemente [1], ..., [n] finden keine Anwendung.
x(?=y) +

Steht für die Zeichen "x", jedoch nur wenn "x" vor "y" steht. Dies wird als lookahead (vorausschauen) bezeichnet.

+ +

Zum Beispiel passt /Mustermann(?=Max)/ auf "Mustermann" nur dann, wenn "Max" dahinter steht. Der Ausdruck /Mustermann(?=Max|Erika)/ passt auf "Mustermann" nur dann, wenn dahinter "Max" oder "Erika" steht. Doch weder "Max" noch "Erika" ist Teil des übereinstimmenden Ergebnisses.

+
x(?!y) +

Passt nur dann auf die Zeichen "x", wenn "x" nicht vor den Zeichen "y" steht. Dies wird auch als negated lookahead (negierte vorausschauende Annahme) bezeichnet.

+ +

Zum Beispiel passt /\d+(?!\.)/ nur dann auf eine Zahl, wenn diese nicht vor einem Dezimalpunkt steht. Der reguläre Ausdruck /\d+(?!\.)/.exec("3.141")  passt auf "141", jedoch nicht auf "3.141".

+
x|y +

Passt auf entweder die Zeichen "x" oder die Zeichen "y".

+ +

Zum Beispiel passt der Ausdruck /grüner|roter/  auf "grüner" in "grüner Apfel" und "roter" in "roter Apfel".

+
{n} +

Das n steht für eine positive ganze Zahl. Das Muster passt exakt auf die Anzahl n des vorangestellten Zeichens.

+ +

Zum Beispiel passt /a{2}/ nicht auf das "a" in "Schokolade",  jedoch auf alle beide a's in "Schokolaade" und die ersten beiden a's in "Schokolaaade".

+
{n,m} +

Wobei n und m positive ganze Zahlen sind. Passt auf mindestes n und höchstens m Vorkommen des vorangestellten Zeichens. Wenn für n oder m eine 0 stehen soll, kann diese auch weggelassen werden.

+ +

Zum Beispiel passt /a{1,3}/ auf nichts in "cndy", jedoch auf das "a" in "candy", die beiden a's in "caandy," und die ersten drei a's in "caaaaaaandy".  Merke: Wenn der Ausdruck auf "caaaaaaandy" angewendet wird, ist die Übereinstimmung "aaa", auch wenn in der Zeichenkette mehr a's enthalten sind.

+
[xyz] +

Die eckigen Klammern kennzeichnen eine Zeichenauswahl. Der Ausdruck stimmt mit allen in den Klammern stehenden Zeichen überein. Mit Hilfe eines Bindestrichs kann ein Bereich (z. B. von a bis z) festgelegt werden. Spezielle Zeichen (wie der Punkt oder das Sternchen) haben keine spezielle Bedeutung innerhalb der eckigen Klammern. Sie müssen nicht "escaped" werden. Escape-Sequenzen funktionieren ebenfalls.

+ +

Zum Beispiel ist [abcd] dasselbe wie [a-d]. Beides passt auf das "b" in "biegen" und das "d" in "denken". Die Ausdrücke /[a-z.]+/ und /[\w.]+/ passen beide auf "test.e.n". Der Punkt ist in diesem Fall kein spezielles Zeichen, weil er innerhalb der eckigen Klammern (Zeichenauswahl) steht.

+
[^xyz] +

Eine negierte oder komplementäre Zeichenauswahl. Das Zirkumflex-Zeichen an erster Stelle innerhalb der Klammern negiert die Zeichenauswahl. Der Ausdruck passt also auf alle Zeichen, die nicht in den Klammern stehen. Es kann mit Hilfe eines Bindestrichs auch ein Bereich von Zeichen (z. B. von a bis z) festgelegt werden. Alle Zeichen, die bei einer normalen Zeichenauswahl funktionieren, funktionieren hier ebenso.

+ +

Zum Beispiel ist [^abc] dasselbe wie [^a-c]. Beide Ausdrücke passen auf das "r" in "brechen" und das "m" in "campen".

+
[\b]Passt auf das Steuerzeichen für die Backspace-Tastet (U+0008), welche den Cursor um eine Position nach links verschiebt und das dort stehende Zeichen entfernt. (Sollte nicht mit \b verwechselt werden.)
\b +

Steht für eine Wortgrenze. Wortgrenzen sind an den Stellen, wo kein anderes Wortzeichen vor oder hinter einem Wortzeichen steht. Eine Wortgrenze wird nicht in die Übereinstimmung aufgenommen. Mit anderen Worten ist die Länge einer Wortgrenze gleich 0 - die Wortgrenze ist der Zwischenraum zwischen einem Wortzeichen und einem Zeichen, das kein Wortzeichen ist oder zwischen einem Wortzeichen und dem Anfang oder Ende der Eingabe. (Sollte nicht mit [\b] verwechselt werden.)

+ +

Beispiele:
+ /\bMon/ passt auf das "Mon" in "Mond" ;
+ /ll\b/ passt nicht auf "ll" in "Falle", weil "ll" nicht vor einer Wortgrenze steht, sondern vor dem Zeichen "e", wobei es sich um ein Wortzeichen handelt.
+ /ond\b/ passt auf das "ond" in "Mond", weil "ond"  das Ende der Zeichenkette ist, also nicht vor einem Wortzeichen steht.
+ Bei /\w\b\w/ wird niemals eine Übereinstimmung gefunden, weil eine Wortgrenze niemals gleichzeitig vor einem Wortzeichen und keinem Wortzeichen stehen kann.

+
\B +

Steht für alle Zeichen, die keine Wortgrenze sind. Dies trifft auf Positionen zu, wo zwei nebeneinanderstehende Zeichen vom selben Typ sind: Entweder sind beide Wortzeichen oder keine Wortzeichen. Der Anfang und das Ende einer Zeichenkette werden nicht als Wortzeichen angesehen, gelten also als Wortgrenzen.

+ +

For example, /\B../ matches 'oo' in "noonday" (, and /y\B./ matches 'ye' in "possibly yesterday."

+ +

Zum Beispiel passt /\B../ auf "at" in "Katze" und /e\B./ auf "ei" in "schlafe ein".

+
\cX +

X ist ein Zeichenbereich von A bis Z. Passt auf ein Steuerzeichen in einer Zeichenkette.

+ +

Zum Beispiel steht /\cM/ für das Steuerzeichen control-M (U+000D) in einer Zeichenkette.

+
\d +

Steht für Ziffern und ist äquivalent zu [0-9].

+ +

Zum Beispiel passt /\d/ oder /[0-9]/ auf "2" in "B2 ist die Zimmernummer."

+
\D +

Steht für alle nicht-Ziffern und ist äquivalent zu [^0-9].

+ +

Zum Beispiel passt /\D/ oder /[^0-9]/ auf "B" in "B2 ist die Zimmernummer."

+
\fSteht für einen Seitenvorschub (engl. form feed (U+000C)).
\nSteht für einen Zeilenbruch (engl. line feed bzw. new line U+000A).
\rSteht für einen Wagenrücklauf (engl. carriage return (U+000D).
\s +

Steht für ein einzelnes Leerraum-Zeichen, einschließlich Leertaste, Tabulator, Seitenvorschub und Zeilenumbruch und ist äquivalent zu [ \f\n\r\t\v​\u00A0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​ \u2005\u2006​\u2007\u2008​\u2009\u200a​\u2028\u2029​\u2028\u2029​ \u202f\u205f​\u3000].

+ +

Zum Beispiel passt /\s\w*/ auf "bar" in "foo bar".

+
\S +

Steht für ein einzelnes Zeichen, das kein Leerraum-Zeichen ist. Äquivalent zu [^ \f\n\r\t\v​\u00A0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​ \u2005\u2006​\u2007\u2008​\u2009\u200a​\u2028\u2029​\u2028\u2029​ \u202f\u205f​\u3000].

+ +

Zum Beispiel passt /\S\w*/ auf "foo" in "foo bar".

+
\tSteht für einen Tabulator (engl. horizontal tab U+0009).
\vSteht für einen vertikalen Tabulator (engl. vertical tabulator (U+000B).
\w +

Steht für ein alphanumerisches Zeichen (Wortzeichen), einschließlich Unterstrich. Äquivalent zu [A-Za-z0-9_].

+ +

Zum Beispiel passt /\w/ auf "a" in "apple" als auch auf "5" in "$5.28" und "3" in "3D".

+
\W +

Steht für ein nicht-alphanumerisches Zeichen (nicht-Wortzeichen). Äquivalent zu [^A-Za-z0-9_].

+ +

Zum Beispiel passt /\W/ oder /[^A-Za-z0-9_]/ auf "%" in "50%".

+
\n +

Stellt einen Rückgriff auf die passenden Zeichen eines eingeklammerten Teilausdrucks dar, wobei n eine positive ganze Zahl ist. Die Zahl steht hierbei für das jeweilige Teilmuster innerhalb eines Klammerpaars an entsprechender Stelle (öffnende Klammern werden gezählt).

+ +

Zum Beispiel passt /Apfel(,)\sOrange\1/ auf "Apfel, Orange," in "Apfel, Orange, Kirsche, Pfirsich".

+
\0Steht für ein NULL-Zeichen (U+0000). Es sollte kein Ziffer dahinter stehen, weil \0<Ziffer> eine Escape-Sequenz für oktale Zahlen ist.
\xhhSteht für das Zeichen mit dem Code hh (zweistellige hexadezimale Zahl).
\uhhhhSteht für das Zeichen mit dem Code hhhh (vierstellige hexadezimale Zahl).
+ +

Das Escapen von Benutzereingaben in einem Stringliteral eines regulären Ausdrucks kann durch folgende Ersetzung getan werden:

+ +
function escapeRegExp (string) {
+    return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& meint den komplett erkannten String
+}
+ +

Benutzung von Klammern

+ +

Klammern werden verwendet, um den eingeklammerten Teil des regulären Ausdrucks zu speichern. Einmal gespeichert kann dieser Teil an anderer Stelle wieder eingesetzt werden, wie unter Benutzung von geklammerten Mustern beschrieben.

+ +

Zum Beispiel beinhaltet der Ausdruck /Kapitel (\d+)\.\d*/ einige maskierte und spezielle Zeichen. Mit den Klammern wird bewirkt, dass die Zeichen, welche mit dem eingeklammerten Muster übereinstimmen, gespeichert werden. Der Ausdruck stimmt genau mit der Zeichenkette "Kapitel " gefolgt von einer oder mehreren Ziffern (\d steht für eine Ziffer und das + (Pluszeichen) bedeutet 1 oder mehr Vorkommen), einem Punkt (der Punkt selbst ist standardmäßig ein spezielles Zeichen, weshalb er maskiert werden muss) und nochmal beliebig vielen Ziffern (\d steht für eine Ziffer und der Stern bedeutet 0 oder mehr Vorkommen) überein. Zusätzlich werden die Klammern eingesetzt, um die erste Ziffer zu speichern.

+ +

Eine Übereinstimmung wird z. B. in "Offenes Kapitel 4.3, Absatz 6" gefunden und dabei wird "4" gespeichert. Auf die Zeichenkette "Kapitel 3 und 4" passt der Ausdruck nicht, weil hinter der ersten Ziffer "3" kein Punkt steht.

+ +

Möchte man einen zusammenhängenden Teil einer Zeichenkette suchen, jedoch nicht speichern, setzt man ?: an den Anfang innerhalb der Klammern. Zum Beispiel stimmt (?:\d+) mit einer oder mehr Ziffern überein, aber diese Ziffern werden nicht gespeichert.

+ +

Arbeiten mit regulären Ausdrücken

+ +

Reguläre Ausdrücke werden mit den Methoden exec und test von RegExp und den Methoden match, replace, search und split von String verwendet. Diese Methoden sind in der JavaScript Referenz beschrieben.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabelle 4.2 Methoden die reguläre Ausdrücke verwenden
MethodDescription
{{jsxref("RegExp.exec", "exec")}}Eine Methode von RegExp, die eine Suche nach einer Übereinstimmung in einer Zeichenkette durchführt. Sie gibt ein Array mit den Übereinstimmungen zurück.
{{jsxref("RegExp.test", "test")}}Eine Methode von RegExp, die eine Zeichenkette auf eine Übereinstimmung überprüft. Sie gibt true oder false zurück.
{{jsxref("String.match", "match")}}Eine Methode von String, die eine Suche nach einer Übereinstimmung in einer Zeichenkette durchführt. Sie gibt ein Array zurück oder null bei keinem Treffer.
{{jsxref("String.search", "search")}}Eine Methode von String, die eine Zeichenkette auf eine Übereinstimmung überprüft. Sie gibt den Index der Übereinstimmung zurück oder -1 bei keinem Treffer.
{{jsxref("String.replace", "replace")}}Eine Methode von String, die eine Suche nach einer Übereinstimmung in einer Zeichenkette durchführt und die Übereinstimmungen durch eine andere Zeichenkette ersetzt.
{{jsxref("String.split", "split")}}Eine Methode von String, die anhand eines regulären Ausdrucks oder einer festen Zeichenkette eine Zeichenkette trennt und die Teile als Array zurückgibt.
+ +

Wenn man nur wissen möchte, ob ein regulärer Ausdruck auf eine Zeichenkette passt, sollten die Methoden test oder search zum Einsatz kommen. Möchte man mehr erfahren, sollte man auf die Methoden exec oder match zurückgreifen (langsamere Ausführungsgeschwindigkeit). Die Methoden exec und match geben ein Array zurück falls Übereinstimmungen gefunden werden und updaten die Eigenschaften des zugehörigen RegExp-Objekts und des vordefinierten RegExp-Objekts. Wenn keine Übereinstimmungen gefunden werden, geben die Methoden null (konvertiert: false) zurück.

+ +

Bei folgendem Beispiel kommt die Methode exec zum Einsatz, um eine Übereinstimmung in einer Zeichenkette zu finden.  

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

Wenn man auf die Eingenschaften des Objekts für den regulären Ausdruck nicht zugreifen möchte, kann man myArray auch direkt wie folgt erzeugen:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz");  // äquivalent zu "cdbbdbsbz".match(/d(b+)d/g);
+
+ +

Möchte man den regulären Ausdruck aus einem String erzeugen, besteht folgende Möglichkeit:

+ +
var myRe = new RegExp("d(b+)d", "g");
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

Bei diesen Skripten werden Übereinstimmungen gefunden. Es wird ein Array zurückgegeben und die Eigenschaften geupdatet, welche in der nachstehenden Tabelle aufgelistet sind.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabelle 4.3 Ergebnisse von regulären Ausdrücken
ObjektEigenschaft oder IndexBeschreibungBei diesem Beispiel
myArray Die übereinstimmende Zeichenfolge und alle gespeicherten Teile.["dbbd", "bb"]
indexDer mit 0 beginnende Index der Übereinstimmung in der Eingabe-Zeichenkette.1
inputDie ursprüngliche Eingabe-Zeichenkette."cdbbdbsbz"
[0]Die zuletzt übereinstimmenden Zeichen."dbbd"
myRelastIndexDer Index bei dem die nächste Suche nach einer Übereinstimmung gestartet wird.  (Diese Eigenschaft wird nur gesetzt, wenn im regulären Ausdruck die Option "g" verwendet wird, wie unter Erweiterte Suche mit Optionen (Flags) beschrieben).5
sourceDer Text des Musters - wird geupdatet wenn der reguläre Ausdruck erstellt wird, nicht bei der Ausführung."d(b+)d"
+ +

Wie das zweite Beispiel zeigt, kann man einen regulären Ausdruck einsetzen, der über einen Objekt-Intializer erstellt wurde, ohne die Zuweisung einer Variablen. Bei dieser Vorgehensweise ist jede Übereinstimmung ein neuer Ausdruck. Aus diesem Grund kann nicht auf die Eigenschaften dieses regulären Ausdrucks zugegriffen werden. Angenommen man hat z. B. dieses Skript:

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+console.log("Der Wert von lastIndex ist " + myRe.lastIndex);
+
+ +

Dann ist die Ausgabe:

+ +
Der Wert von lastIndex ist 5
+
+ +

Hat man nun aber dieses Skript:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+console.log("Der Wert von lastIndex ist " + /d(b+)d/g.lastIndex);
+
+ +

Dann ist die Ausgabe:

+ +
Der Wert von lastIndex ist 0
+
+ +

Die einzelnen Vorkommen der Zeichenfolgen, die mit /d(b+)d/g übereinstimmen sind bei den beiden Anweisungen verschiedene Objekte und haben dementsprechend auch verschiedene Werte bei der jeweiligen Eigenschaft lastIndex. Falls man auf die Eigenschaften eines Objekts eines regulären Ausdrucks zugreifen möchte, sollte man diesen vorher einer Variablen zuweisen.

+ +

Benutzung von geklammerten Mustern

+ +

Klammern werden verwendet, um einen Teil der Zeichen, die mit dem regulären Ausdruck übereinstimmen, zu speichern. Zum Beispiel stimmt /a(b)c/ mit der Zeichenfolge "abc" überein und "b" wird gespeichert. Um die gespeicherten Zeichen wieder abzurufen, verwendet man die Array-Elemente [1], ..., [n].

+ +

Die Anzahl der möglichen speicherbaren Teile ist nicht limitiert. Das Array, welches zurückgegeben wird, enthält alle gespeicherten Übereinstimmungen. Die folgenden Beispiele zeigen auf, wie man geklammerte Muster einsetzt.

+ +

Beispiel 1

+ +

Das folgende Skript benutzt die Methode replace(), um Wörter in einer Zeichenkette auszutauschen. Die beiden Muster für die Wörter (\w+) wurden geklammert, damit die Wörter gespeichert werden. Anschließend werden im Ersetzungstext diese gespeicherten Wörter mit $1 und $2 wieder eingesetzt.

+ +
var re = /(\w+)\s(\w+)/;
+var str = "Jonas Schmidt";
+var newstr = str.replace(re, "$2, $1");
+console.log(newstr);
+
+ +

Die Ausgabe ist "Schmidt, Jonas".

+ +

Erweiterte Suche mit Optionen (Flags)

+ +

Reguläre Ausdrücke kennen vier verschiedene Optionen (Flags), die es z. B. erlauben global nach Übereinstimmungen zu suchen oder die Berücksichtigung der Groß- und Kleinschreibweise zu deaktivieren. Zur Aktivierung der globalen Suche wird das Flag g eingesetzt. Die Berücksichtigung der Groß- und Kleinschreibweise (engl. case-insensitive ) wird mit dem Flag i abgeschaltet. Die mehrzeilige Suche (engl. multiline) wird mit dem Flag m aktiviert und eine "sticky" Suche, wobei die Übereinstimmung an der aktuellen Postion im Eingabe-Zeichenkette zutreffen muss, wird mit dem Flag y aktiviert. Diese Optionen können getrennt oder gemeinsam verwendet und in beliebiger Reihenfolge angegeben werden. Die Buchstaben werden einfach an den regulären Ausdruck angehängt.

+ +

{{ Fx_minversion_note(3, "Die Unterstützung für das Flag y wurde bei Firefox 3 hinzugefügt. Wenn y aktiviert ist, schlägt die Suche fehl, wenn es keine Übereinstimmung an der aktuellen Position innerhalb der Eingabe-Zeichenkette gibt.") }}

+ +

Syntax für die Verwendung von Optionen:

+ +
var re = /Muster/Optionen;
+
+ +

oder

+ +
var re = new RegExp("Muster", "Optionen");
+
+ +

Die Optionen sind ein integraler Bestandteil des regulären Ausdrucks. Sie können nicht im Nachhinein entfernt oder hinzugefügt werden.

+ +

Zum Beispiel wird mit re = /\w+\s/g ein regulärer Ausdruck erstellt, der auf ein oder mehr Zeichen, gefolgt von einem Leerraum, passt. Nach diesem Muster wird über die ganze Zeichenkette hinweg gesucht.

+ +
var re = /\w+\s/g;
+var str = "fee fi fo fum";
+var myArray = str.match(re);
+console.log(myArray);
+
+ +

Hier ist die Ausgabe: ["fee ", "fi ", "fo "]. Bei diesem Beispiel könnte man die Zeile:

+ +
var re = /\w+\s/g;
+
+ +

mit folgender austauschen:

+ +
var re = new RegExp("\\w+\\s", "g");
+
+ +

und würde dasselbe Ergebnis erhalten.

+ +

Die Option m sorgt dafür, dass eine mehrzeilige Eingabe auch als solche interpretiert wird. Wird die Option m angegeben, passen die speziellen Zeichen ^ und $ auf den Anfang oder das Ende jeder Zeile der Eingabe, anstatt nur auf den Anfang und das Ende der gesamten Eingabe.

+ +

Beispiele

+ +

Das folgende Beispiel zeigt einige Einsatzmöglichkeiten von regulären Ausdrücken.

+ +

Ändern der Reihenfolge in einer Zeichenkette

+ +

Das folgende Beispiel veranschaulicht die Anordnung von regulären Ausdrücken und die Verwendung der Methoden string.split() und string.replace(). Im Beispiel wird eine schlecht formatierte Eingabe mit Personennamen (Vorname zuerst), die durch Leerzeichen, Tabulatoren und exakt ein Semikolon getrennt sind, bereinigt. Außerdem wird die Reihenfolge des jeweiligen Namens herumgedreht (Nachname zuerst) und die Liste nach Nachnamen sortiert.

+ +
// Die Zeichenkette beinhaltet mehrere Leerzeichen und Tabulatoren
+// und könnte mehrere Leerzeichen zwischen vor und Nachnamen enthalten.
+
+var names = "Lieschen Müller ;Erika Mustermann; Michel Deutscher ; Otto Normalverbraucher ; ";
+
+var output = ["---------- Original String\n", names + "\n"];
+
+// Erstellen von zwei regulären Ausdrücken und eines Arrays.
+// Die Eingabe-Zeichenkette wird in Array-Elemente zerlegt.
+
+// Muster: Möglicherweise ein Leerraum, dann ein Semikolon
+// und möglicherweise nochmal ein Leerraum (0 oder mehr).
+var pattern = /\s*;\s*/;
+
+// Splitten der Zeichenkette in einzelne Teile anhand des Musters und
+// speichern der Teile in einem Array mit Namen nameList.
+var nameList = names.split(pattern);
+
+// Neuer regulärer Ausdruck: ein oder mehr alphanumerische Zeichen,
+// dann mindestens ein Leerraum und nochmal mindestens ein Wortzeichen.
+// Klammern zum Speichern; Rückgriff auf gespeicherte Teile später.
+pattern = /(\w+)\s+(\w+)/;
+
+// Neues Array zum Speichern der bearbeiteten Namen.
+var bySurnameList = [];
+
+// Anzeigen des Arrays und befüllen des neuen Arrays
+// mit durch Komma getrennten Namen (Nachname zuerst).
+// Die Methode replace() entfernt alles, was mit dem Muster übereinstimmt
+// und ersetzt es durch den an zweiter Stelle angegebenen String,
+// bestehend aus den gespeicherten Teilen.
+// Zuerst wird der zweite Teil ($2) eingesetzt und anschließend durch Komma
+// und Leerzeichen getrennt der erste Teil ($1).
+
+output.push("---------- Nach Teilung durch regulären Ausdruck");
+
+var i, len;
+for (i = 0, len = nameList.length; i < len; i++){
+  output.push(nameList[i]);
+  bySurnameList[i] = nameList[i].replace(pattern, "$2, $1");
+}
+
+// Anzeigen des neuen Arrays.
+output.push("---------- Namen reserviert");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+// Sortieren anhand des Nachnamens und anzeigen des neuen Arrays.
+bySurnameList.sort();
+output.push("---------- Sortiert");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+output.push("---------- End");
+
+console.log(output.join("\n"));
+
+ +

Benutzung von speziellen Zeichen zur Verifizierung von Eingaben

+ +

Beim nachstehenden Beispiel wird der Benutzer aufgefordert, eine Telefonnummer einzugeben. Wenn der Benutzer den "Prüfen"-Button drückt, überprüft das Skript die Validität der Nummer. Sofern dann sichergestellt ist, dass es sich um eine Telefonnummer handelt (die Eingabe stimmt mit dem Muster des regulären Ausdrucks überein), zeigt das Skript eine Nachricht, um dem Benutzer zu danken und die Nummer zu bestätigen. Wenn die Nummer nicht valide ist (nicht mit dem Muster des regulären Ausdrucks übereinstimmt), wird der Benutzer ebenfalls mit einer Nachricht darüber informiert.

+ +

Das Muster des reguläre Ausdruck setzt sich folgendermaßen zusammen: Keine oder eine öffnende Klammer, \(?, gefolgt von drei Ziffern \d{3}, gefolgt von keiner oder einer schließenden Klammer \)?, gefolgt von einem Bindestrich, Schrägstrich, oder Punkt (falls vorhanden wird das Zeichen gespeichert) ([-\/\.]), gefolgt von drei Ziffern \d{3}, gefolgt (falls vorhanden) von dem gespeicherten Zeichen (Bindestrich, Schrägstrich oder Punkt) \1, gefolgt von vier Ziffern \d{4}.

+ +

Das Event Change wird ausgelöst, wenn der Benutzer die Enter-Taste drückt, um die Eingabe (den Wert für RegExp.input) zu bestätigen.

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+    <meta http-equiv="Content-Script-Type" content="text/javascript">
+    <script type="text/javascript">
+      var re = /\(?\d{3}\)?([-\/\.])\d{3}\1\d{4}/;
+      function testInfo(phoneInput){
+        var OK = re.exec(phoneInput.value);
+        if (!OK)
+          window.alert(RegExp.input + " ist keine Telefonnummer mit Vorwahl!");
+        else
+          window.alert("Danke! Ihre Telefonnummer ist " + OK[0]);
+      }
+    </script>
+  </head>
+  <body>
+    <p>Bitte ihre Telefonnummer (mit Vorwahl) eingeben und den "Prüfen"-Button anklicken.
+        <br>Das Format ist z.B. ###-###-####.</p>
+    <form action="#">
+      <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Prüfen</button>
+    </form>
+  </body>
+</html>
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Textformatierung", "Web/JavaScript/Guide/Indexed_collections")}}

diff --git a/files/de/web/javascript/guide/schleifen_und_iterationen/index.html b/files/de/web/javascript/guide/schleifen_und_iterationen/index.html new file mode 100644 index 0000000000..9f351abcd9 --- /dev/null +++ b/files/de/web/javascript/guide/schleifen_und_iterationen/index.html @@ -0,0 +1,337 @@ +--- +title: Schleifen und Iterationen +slug: Web/JavaScript/Guide/schleifen_und_iterationen +tags: + - Guide + - JavaScript + - Loop + - Syntax + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}
+ +

Schleifen sind ein einfaches Werkzeug, um einzelne Schritte wiederholt auszuführen. Dieses Kapitel des JavaScript Guide stellt die verschiedenen Statements für Iterationen vor, welche in JavaScript zur Verfügung stehen.

+ +

Man kann sich Schleifen wie eine Computerversion des Spiels vorstellen, bei dem man jemandem sagt, er soll x Schritte in eine Richtung und dann y Schritte in eine andere Richtung gehen. So kann zum Beispiel die Aussage "Gehe fünf Schritte nach Osten" mit Hilfe von Schleifen so ausgedrückt werden:

+ +
var schritt;
+for (schritt = 0; schritt < 5; schritt++) {
+  // Laufe 5 mal, mit den Werten von Schritt 0 bis 4
+  console.log('Gehe einen Schritt nach Osten');
+}
+
+ +

Es gibt viele verschiedene Arten von Schleifen, doch im Wesentlichen verrichten alle die gleiche Aufgabe: sie führen eine Aktion für eine bestimmte Anzahl an Wiederholungen aus (diese Anzahl kann auch 0 sein). Dabei ermöglichen die verschiedenen Arten von Schleifen unterschiedliche Anfangs- und Endpunkte festzulegen. Es gibt zahlreiche Situationen in denen eine Art von Schleifen einfacher zum Ergebnis führt, als eine andere.

+ +

JavaScript stellt folgende Statements für Schleifen zur Verfügung:

+ + + +

for Statement

+ +

Eine  {{jsxref("statements/for","for Schleife")}} wird so lange durchlaufen, bis eine bestimmte Bedingung den Wert false liefert. Die for Schleife in JavaScript ist vergleichbar mit der in Java und C. Ein for Statement sieht wie folgt aus:

+ +
for ([initialerAusruck]; [Bedingung]; [erhöhenderAusdruck])
+  Anweisung
+
+ +

Bei der Ausführung einer for Schleife geschieht folgendes:

+ +
    +
  1. Der Ausdruck zur Initialisierung der Schleife initialerAsudruck, wird ausgeführt, sofern dieser existiert. Dieser Ausdruck initialisiert einen oder mehrere Schleifenzähler, wobei die Syntax beliebig komplexe Ausdrücke zulässt. In diesem Ausdruck können auch Variablen deklariert werden.
  2. +
  3. Die Bedingung Bedingung wird geprüft. Wenn die Auswertung von Bedingung den Wert true ergibt, werden die Anweisungen innerhalb der Schleife ausgeführt. Ergibt die Prüfung hingegen false, wird die Schleife verlassen. Bleibt die Bedingung leer, wird immer der Wert true angenommen.
  4. +
  5. Die Anweisung wird ausgeführt. Um mehrere Anweisungen auszuführen, werden Block-Anweisungen ({ ... }) verwendet, um diese zu gruppieren.
  6. +
  7. Wenn vorhanden, wird der Ausdruck erhöhenderAusdruck ausgeführt.
  8. +
  9. Geht zu Schritt 2 zurück.
  10. +
+ +

Beispiel

+ +

Die folgende Funktion enthält ein for Statement, welche die Anzahl der ausgewählten Optionen aus einer Auswahlliste (ein {{HTMLElement("select")}}, welches eine Mehrfachauswahl erlaubt) ermittelt. Das for Statement deklariert eine Variable i und initialisiert diese mit dem Wert 0. Sie prüft ob i kleiner als die Anzahl der verfügbarer Optionen des <select> Elements ist, führt das nachfolgende if Statement aus und erhöht i bei jedem Schleifendurchlauf um 1.

+ +
<form name="selectForm">
+  <p>
+    <label for="musicTypes">Choose some music types, then click the button below:</label>
+    <select id="musicTypes" name="musicTypes" multiple="multiple">
+      <option selected="selected">R&B</option>
+      <option>Jazz</option>
+      <option>Blues</option>
+      <option>New Age</option>
+      <option>Classical</option>
+      <option>Opera</option>
+    </select>
+  </p>
+  <p><input id="btn" type="button" value="How many are selected?" /></p>
+</form>
+
+<script>
+function howMany(selectObject) {
+  var numberSelected = 0;
+  for (var i = 0; i < selectObject.options.length; i++) {
+    if (selectObject.options[i].selected) {
+      numberSelected++;
+    }
+  }
+  return numberSelected;
+}
+
+var btn = document.getElementById('btn');
+btn.addEventListener('click', function(){
+  alert('Number of options selected: ' + howMany(document.selectForm.musicTypes))
+});
+</script>
+
+
+ +

do...while Statement

+ +

Das {{jsxref("statements/do...while", "do...while")}} Statement wiederholt eine bestimmte Anweisung, bis eine Bedingung false ergibt. Ein do...while Statement sieht wie folgt aus:

+ +
do
+  anweisung
+while (bedingung);
+
+ +

amweisung wird dabei einmal ausgeführt, bevor die Bedingung geprüft wird. Um mehrere Anweisungen auszuführen, werden diese als Block Statement ({ ... }) gruppiert. Wenn bedingung true ist, wird die Anweisung erneut ausgeführt. Nach jeder Ausführung der Anweisungen, wird die Bedingung erneut geprüft. Sobald bedingung false ergibt, endet die Ausführung der Schleife und die nächste Anweisung nach der do...while Schleife aus wird ausgeführt.

+ +

Beispiel

+ +

Im folgenden Beispiel wird die Schleife mindestens einmal ausgeführt. Anschliessend wird die Schleife so oft durchlaufen, bis i nicht mehr kleiner als 5 ist.

+ +
var i = 0;
+do {
+  i += 1;
+  console.log(i);
+} while (i < 5);
+ +

while Statement

+ +

Ein {{jsxref("statements/while","while")}} Statement wird solange ausgeführt, wie eine bestimmte Bedingung true ergibt. Ein while Statement sieht wie folgt aus:

+ +
while (bedingung)
+  anweisung
+
+ +

Wenn die Bedingung false ist, wird die Schleife nicht weiter durchlaufen und die nächste Anweisung nach der while Schleife wird ausgeführt.

+ +

Die Prüfung der Bedingung erfolgt, bevor die Anweisungen innerhalb der Schleife ausgeführt werden. Nur wenn die Bedingung true ist, wird die Schleife ausgeführt, wobei anschliessend eine erneute Prüfung der Bedingung erfolgt. Ergibt die Bedingung false, wir mit der Anweisungen nach der while Schleife fortgefahren.

+ +

Um mehrere Anweisungen auszuführen, werden diese in einer block Anweisung ({ ... }) gruppiert.

+ +

Beispiel 1

+ +

Die folgende while Schleife wird so lange ausgeführt, wie n kleiner als 3 ist.

+ +
var n = 0;
+var x = 0;
+while (n < 3) {
+  n++;
+  x += n;
+}
+
+ +

Mit jedem Schleifendurchlauf wird n um 1 erhöht. Der Wert von n wird dann zum Wert von x addiert. Dadurch nehmen x und n die folgenden Werte an:

+ + + +

Nach dem dritten Durchlauf ist die Bedingung n < 3 nicht mehr true und die Schleife wird verlassen.

+ +

Beispiel 2

+ +

Endlosschleifen müssen vermieden werden. Es ist immer sicherzustellen, dass die Bedingung irgendwann false ergibt, da die Schleife ansonsten nie endet. Die Anweisung in der folgenden while Schleife wird für immer ausgeführt, weil die Bedingung nie false ergibt:

+ +
while (true) {
+  console.log('Hello, world!');
+}
+ +

Label Statement

+ +

Ein {{jsxref("statements/label","label")}} stellt ein Statement mit einem Bezeichner bereit, welches es ermöglicht auf eine bestimmte stelle im Programm zu verweisen. So kann ein Label zum Beispiel dafür verwendet werden eine Schleife zu identifizieren und dann mit break oder continue festzulegen ob diese beendet oder weiter durchlaufen werden soll.

+ +

Die Syntax des Label Statement sieht wie folgt aus:

+ +
label :
+   anweisung
+
+ +

Der Wert von label kann jede Bezeichnung sein, der kein reserviertes JavaScript Schlüsselwort ist. Die anweisung die mit dem Label identifiziert wird, kann jede beliebige Anweisung sein.

+ +

Beispiel

+ +

In diesem Beispiel identifiziert das Label markLoop eine while Schleife.

+ +
markLoop:
+while (theMark == true) {
+   doSomething();
+}
+ +

break Statement

+ +

Um eine Schleife oder ein switch Statement zu beenden, verwendet man das {{jsxref("statements/break","break")}} Statement in Verbindung mit dem Label Statement.

+ + + +

Die Syntax von break sieht wie folgt aus:

+ +
break [label];
+
+ +

Die erste Variante der Syntax beendet die innerste Schleife oder das innerste switch Statement. Die zweite Variante beendet eine bestimmte Anweisung.

+ +

Beispiel 1

+ +

Das folgende Beispiel durchläuft die Elemente in einem Array, bis ein Element mit dem Wert von theValue gefunden wird:

+ +
for (var i = 0; i < a.length; i++) {
+  if (a[i] == theValue) {
+    break;
+  }
+}
+ +

Beispiel 2: break mit einem Label

+ +
var x = 0;
+var z = 0;
+labelCancelLoops: while (true) {
+  console.log('Outer loops: ' + x);
+  x += 1;
+  z = 1;
+  while (true) {
+    console.log('Inner loops: ' + z);
+    z += 1;
+    if (z === 10 && x === 10) {
+      break labelCancelLoops;
+    } else if (z === 10) {
+      break;
+    }
+  }
+}
+
+ +

continue Statement

+ +

Das {{jsxref("statements/continue","continue")}} Statement kann eingesetzt werden, um eine while, do-while, for Schleife oder ein Statement mit einem Label erneut auszuführen.

+ + + +

Die Syntax des continue Statement sieht wie folgt aus:

+ +
continue [label];
+
+ +

Beispiel 1

+ +

Das folgende Beispiel zeigt eine while Schleife, mit einem continue Statement, die weiter ausgeführt wird, wenn i den Wert 3 hat. Dadurch erhält n die Werte 1, 3, 7 und 12.

+ +
var i = 0;
+var n = 0;
+while (i < 5) {
+  i++;
+  if (i == 3) {
+    continue;
+  }
+  n += i;
+}
+
+ +

Beispiel 2

+ +

Eine Anweisung mit dem Label checkiandj enthält eine Anweisung mit dem Label checkj. Wenn continue erreicht wird, bricht das Programm den aktuellen Schleifendurchlauf von checkj ab und setzt die Ausführung beim nächsten Durchlauf fort. Immer wenn continue erreicht wird, wird checkj erneut ausgeführt, bis dessen Bedingung false zurückliefert. Wird false zurückgeliefert, wird der Rest der checkiandj Anweisung vollendet und checkiandj wird wiederholt, bis dessen Bedingung false zurückgibt. Wird false zurückgegeben, wird das Programm bei der Anweisung nach checkiandj fortgesetzt.

+ +

Wenn continue ein Label checkiandj hätte, würde das Programm am Anfang der checkiandj Anweisung fortgesetzt werden.

+ +
var i = 0;
+var j = 10;
+checkiandj:
+  while (i < 4) {
+    console.log(i);
+    i += 1;
+    checkj:
+      while (j > 4) {
+        console.log(j);
+        j -= 1;
+        if ((j % 2) == 0) {
+          continue checkj;
+        }
+        console.log(j + ' is odd.');
+      }
+      console.log('i = ' + i);
+      console.log('j = ' + j);
+  }
+ +

for...in Statement

+ +

Das {{jsxref("statements/for...in","for...in")}} Statement durchläuft eine bestimmte Variable über alle aufzählbaren Eigenschaften eines Objekts. Für jede einzelne Eigenschaft führt JavaScript die entsprechende Anweisung aus. Ein for...in Statement sieht wie folgt aus:

+ +
for (variable in object) {
+  statements
+}
+
+ +

Beispiel

+ +

Die folgende Funktion nimmt als Argument ein Objekt und dessen Namen entgegen. Anschliessend durchläuft sie alle Eigenschaften des Objekts und liefert einen String zurück, der alle Namen und Werte der Eigenschaften des Objekts enthält.

+ +
function dump_props(obj, obj_name) {
+  var result = '';
+  for (var i in obj) {
+    result += obj_name + '.' + i + ' = ' + obj[i] + '<br>';
+  }
+  result += '<hr>';
+  return result;
+}
+
+ +

Für ein Objekt car mit den Eigenschaften make und model, sieht das Ergebnis wie folgt aus:

+ +
car.make = Ford
+car.model = Mustang
+
+ +

Arrays

+ +

Auch wenn es nahe liegt diesen Weg zu verwenden, um die Elemente eines {{jsxref("Array")}}s zu durchlaufen, würde das for...in Statement die Namen der definierten Werte und den numerischen Index zurückliefern. Daher ist es besser eine normale {{jsxref("statements/for","for")}} Schleifen mit einem numerischen Index zu verwenden, wenn Arrays durchlaufen werden sollen, da das for...in Statement neben den benutzerdefinierten Elementen auch die Eigenschaften des Arrays durchläuft, wenn man Methoden oder Eigenschaften hinzufügt oder ändert.

+ +

for...of Statement

+ +

Das {{jsxref("statements/for...of","for...of")}} Statement erstellt eine Schleife, die alle iterable objects (inklusive {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, {{jsxref("functions/arguments","arguments")}} Objekt, etc.) durchläuft und die Anweisungen ausführt, die mit dem Wert des Durchlaufes für jede Eigenschaft übereinstimmt.

+ +
for (variable of object) {
+  statement
+}
+ +

Das folgende Beispiel zeigt den Unterschied zwischen der for...of Schleife und der {{jsxref("statements/for...in","for...in")}} Schleife. Während for...in die Namen der Eigenschaften durchläuft, durchläuft for...of die Werte der Eigenschaft:

+ +
var arr = [3, 5, 7];
+arr.foo = 'hello';
+
+for (var i in arr) {
+   console.log(i); // logs "0", "1", "2", "foo"
+}
+
+for (var i of arr) {
+   console.log(i); // logs 3, 5, 7
+}
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}

diff --git a/files/de/web/javascript/guide/textformatierung/index.html b/files/de/web/javascript/guide/textformatierung/index.html new file mode 100644 index 0000000000..48c45c9871 --- /dev/null +++ b/files/de/web/javascript/guide/textformatierung/index.html @@ -0,0 +1,257 @@ +--- +title: Textformatierung +slug: Web/JavaScript/Guide/Textformatierung +tags: + - Guide + - JavaScript + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Text_formatting +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}
+ +

Dieses Kapitel gibt eine Einführung darüber, wie in JavaScript mit Strings (Zeichenfolgen) und Texten gearbeitet wird.

+ +

Strings

+ +

JavaScript's Datentyp {{Glossary("String")}} wird verwendet, um textuelle Daten zu repräsentieren. Es handelt sich um eine Reihe von Elementen, die ganzzahlige 16-Bit-Werte ohne Vorzeichen (UTF-16 Code Units) sind. Jedes Element belegt eine Position im String. Das erste Element befindet hat den Index 0, das nächste den Index 1 usw. Die Länge des Strings ist die Anzahl der Elemente, die darin enthalten sind. Strings können über String-Literale oder String-Objekte erzeugt werden.

+ +

ACHTUNG: Beim Bearbeiten dieser Seite keine Zeichen mit Zeichencode größer als U+FFFF einfügen, bis MDN bug 857438 behoben wurde ( https://bugzilla.mozilla.org/show_bug.cgi?id=857438 ).

+ +

String Literale

+ +

Einfache Strings können mittels einfacher oder doppelter Anführungszeichen erzeugt werden:

+ +
'foo'
+"bar"
+ +

Anspruchsvollere Strings können mit Escape-Sequenzen erstellt werden:

+ +

Hexadezimale Escape-Sequenzen

+ +

Die Zahl nach \x wird als hexadecimale Zahl interpretiert.

+ +
'\xA9' // "©"
+
+ +

Unicode Escape-Sequenzen

+ +

Unicode Escape-Sequenzen erfordern mindestens vier hexadezimale Ziffern nach \u.

+ +
'\u00A9' // "©"
+ +

Unicode Code Point Escapes

+ +

Diese sind neu in ECMAScript 2015. Mit Unicode Code Point Maskierung können beliebige Zeichen durch Maskierungssequenzen mit hexadezimalen Zahlen erzeugt werden, sodass die Verwendung von Unicode Code Points bis zu 0x10FFFF möglich ist. Mit einfachen Unicode Maskierungssequenz ist es oft notwendig, Surrogate-Hälften als zwei getrennte Maskierungssequenzen zu schreiben, um dasselbe Ergebnis zu erhalten.

+ +

Siehe auch {{jsxref("String.fromCodePoint()")}} oder {{jsxref("String.prototype.codePointAt()")}}.

+ +
'\u{2F804}'
+
+// das gleiche mit einfachen Unicode Escape-Sequenzen
+'\uD87E\uDC04'
+ +

String Objekte

+ +

Das {{jsxref("String")}} Objekt ist ein Wrapper für den primitiven Datentyp String.

+ +
var s = new String('foo'); // Erstellt ein String object
+console.log(s); // Ausgabe: {'0': 'f', '1': 'o', '2': 'o'}
+typeof s; // Gibt 'object' zurück
+
+ +

Beliebige Methoden des String Objekts können als Methoden eines String-Literals aufgerufen werden – JavaScript wandelt das String-Literal automatisch in ein temporäres String Objekt um, ruft die Methode auf und verwirft das temporäre String Objekt anschließend. Außerdem kann die String.length Eigenschaft mit einem String-Literal verwendet werden.

+ +

String-Literale sollten verwendet werden, außer es wird tatsächlich ein String Objekt benötigt, da String Objekte unerwartetes Verhalten aufweisen können. Beispielsweise:

+ +
var s1 = '2 + 2'; // Erzeugt ein String-Literal
+var s2 = new String('2 + 2'); // Erzeugt ein String Objekt
+eval(s1); // Gibt die Zahl 4 zurück
+eval(s2); // Gibt den String "2 + 2" zurück
+ +

Ein String Objekt hat eine Eigenschaft length, die die Anzahl von der UTF-16 Code Units im String angibt. Der folgende Code beispielsweise weist der Variable x den Wert 13 zu, da "Hello, World!" aus 13 Zeichen besteht. Jedes dieser Zeichen wird durch eine UTF-16 Code Unit dargestellt. Auf jede dieser Code Units kann durch eckige Klammern zugegriffen werden. Es können jedoch keine Zeichen geändert werden, da Strings unveränderbare Array-ähnliche Objekte sind:

+ +
var mystring = 'Hello, World!';
+var x = mystring.length;
+mystring[0] = 'L'; // hat keinen Effekt
+mystring[0]; // gibt "H" zurück
+
+ +

Zeichen mit einem Unicode-Wert größer als U+FFFF (wie z.B. manche seltene chinesiche/japanische/koreanische/vietnamesische Zeichen und einige Emoji) werden in UTF-16 als zwei Surrogate Code Units gespeichert. Ein String, der nur aus einem Zeichen, U+1F600 ("Emoji grinning face"), besteht, hätte die Länge 2. Der Zugriff auf einzelne Code Units in einem solchen String kann zu unerwünschten Effekten führen, wie z.B. die Entstehung von String mit unvollständigen Surrogate Code Units, was gegen den Unicode Standard verstößt. (Beispiele dafür sollten zu dieser Seite hinzugefügt werden, sobald MDN bug 857438 behoben wurde.) Siehe auch {{jsxref("String.fromCodePoint()")}} oder {{jsxref("String.prototype.codePointAt()")}}.

+ +

Ein String Objekt verschiedenste Methoden, unter anderem auch welche, die den String in abgewandelter Form zurückgeben, wie z.B. substring und toUpperCase.

+ +

Die folgende Tabelle gibt eine Zusammenfassung der Methoden von {{jsxref("String")}} Objekten.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Methoden von String

+
MethodeBeschreibung
{{jsxref("String.charAt", "charAt")}}, {{jsxref("String.charCodeAt", "charCodeAt")}}, {{jsxref("String.codePointAt", "codePointAt")}}Gibt das Zeichen oder den Zeichencode an der angegebenen Stelle im String zurück.
{{jsxref("String.indexOf", "indexOf")}}, {{jsxref("String.lastIndexOf", "lastIndexOf")}}Gibt die erste bzw. letzte Position des angegebenen Teilstrings im String zurück.
{{jsxref("String.startsWith", "startsWith")}}, {{jsxref("String.endsWith", "endsWith")}}, {{jsxref("String.includes", "includes")}}Gibt zurück, ob ein String mit dem angegebenen Teilstring beginnt, endet oder den Teilstring enthält.
{{jsxref("String.concat", "concat")}}Fügt die beiden Strings zusammen und gibt diesen neuen String zurück.
{{jsxref("String.fromCharCode", "fromCharCode")}}, {{jsxref("String.fromCodePoint", "fromCodePoint")}}Erstellt einen String aus den angegebenen Unicode Codes. Es handelt sich um eine Methode der Klasse String, nicht die einer String Instanz.
{{jsxref("String.split", "split")}}Teilt ein String Objekt in ein Array von Teilstrings.
{{jsxref("String.slice", "slice")}}Gibt einen Ausschnitt des Strings als neuen String zurück.
{{jsxref("String.substring", "substring")}}, {{jsxref("String.substr", "substr")}}Gibt einen Ausschnitt des Strings zurück, der entweder durch Angabe der Start- und Endindizes oder durch Angabe des Startindex und einer Länge gebildet wird.
{{jsxref("String.match", "match")}}, {{jsxref("String.replace", "replace")}}, {{jsxref("String.search", "search")}}Verwendet Regular Expressions um Übereinstimmungen mit einem Suchmuster zu finden oder Teile des Strings zu ersetzen.
{{jsxref("String.toUpperCase", "toUpperCase")}}, {{jsxref("String.toLowerCase", "toLowerCase")}} +

Wandelt einen String in Groß- bzw Kleinschreibung um und gibt das Ergebnis als neuen String zurück.

+
{{jsxref("String.normalize", "normalize")}}Gibt die Unicode Normalization Form des Strings zurück.
{{jsxref("String.repeat", "repeat")}}Gibt einen String zurück, in dem der ursprüngliche String mehrfach aneinandergereiht wurde.
{{jsxref("String.trim", "trim")}}Entfernt Leerzeichen vom Anfang und vom Ende des Strings.
+ +

Mehrzeilige Template-Strings

+ +

Template-Strings sind String-Symbole, die eingebettete Ausdrücke erlauben. Mit diesen Ausdrücken können mehrzeilige Strings und String-Interpolation genutzt werden.

+ +

Template-Strings sind anstelle von doppelten bzw. einfachen Anführungszeichen in Back-Ticks (` `) (grave accent) eingeschlossen. Template-Strings können Platzhalter beinhalten, die durch das Dollarsymbol gefolgt von geschweiften Klammern gekennzeichnet sind (${expression}).

+ +

Mehrzeilige Strings

+ +

Alle Zeichen, die einen Zeilenumbruch einleiten und sich zwischen Back-Ticks befinden, werden als Teil des Template Strings verwendet. Bei normalen Strings muss die folgende Syntax genutzt werden, um Strings mit Zeilenumbrücken über mehrere Codezeilen zu definieren:

+ +
console.log('string text line 1\n\
+string text line 2');
+// "string text line 1
+// string text line 2"
+ +

Um dasselbe Ergebnis mit Template-Strings zu erreichen, kann die folgende Schreibweise genutzt werden:

+ +
console.log(`string text line 1
+string text line 2`);
+// "string text line 1
+// string text line 2"
+ +

Erweiterung von Ausdrücken

+ +

Um Ausdrücke in normale Strings einzufügen, müsste die folgende Syntax genutzt werden:

+ +
var a = 5;
+var b = 10;
+console.log('Fifteen is ' + (a + b) + ' and\nnot ' + (2 * a + b) + '.');
+// "Fifteen is 15 and
+// not 20."
+ +

Mit Template-Strings können nun die syntaktischen Vorteile genutzt werden um solche Ersetzungen leserlicher zu machen:

+ +
var a = 5;
+var b = 10;
+console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`);
+// "Fifteen is 15 and
+// not 20."
+ +

Mehr Informationen sind unter Template-Strings in der JavaScript-Referenz nachzulesen. 

+ +

Internationalization

+ +

Das {{jsxref("Intl")}} Objekt ist der Namespace für das ECMAScript Internationalization API, welches sprachabhängige String-Vergleiche, Zahlen-, Datums- und Uhrzeitformate bereitstellt. Die Konstruktoren für {{jsxref("Collator")}}, {{jsxref("NumberFormat")}} und {{jsxref("DateTimeFormat")}} Objekte sind Eigenschaften des Intl Objekts.

+ +

Datums- und Uhrzeitformatierung

+ +

Das {{jsxref("DateTimeFormat")}} Objekt hilft bei der Datums- oder Uhrzeitformatierung. Im folgenden Beispiel wird ein Datum für amerikanisches Englisch formatiert. (Das Ergebnis variiert je nach eingestellter Zeitzone.)

+ +
var msPerDay = 24 * 60 * 60 * 1000;
+
+// July 17, 2014 00:00:00 UTC.
+var july172014 = new Date(msPerDay * (44 * 365 + 11 + 197));
+
+var options = { year: '2-digit', month: '2-digit', day: '2-digit',
+                hour: '2-digit', minute: '2-digit', timeZoneName: 'short' };
+var americanDateTime = new Intl.DateTimeFormat('en-US', options).format;
+
+console.log(americanDateTime(july172014)); // 07/16/14, 5:00 PM PDT
+
+ +

Zahlenformatierung

+ +

Das {{jsxref("NumberFormat")}} Objekt hilft bei der Formatierung von Zahlen, wie z.B. Währungen.

+ +
var gasPrice = new Intl.NumberFormat('en-US',
+                        { style: 'currency', currency: 'USD',
+                          minimumFractionDigits: 3 });
+
+console.log(gasPrice.format(5.259)); // $5.259
+
+var hanDecimalRMBInChina = new Intl.NumberFormat('zh-CN-u-nu-hanidec',
+                        { style: 'currency', currency: 'CNY' });
+
+console.log(hanDecimalRMBInChina.format(1314.25)); // ¥ 一,三一四.二五
+
+ +

Sortierung

+ +

Das {{jsxref("Collator")}} Objekt hilft beim Vergleichen und Sortieren von Strings.

+ +

Zum Beispiel gibt es im Deutschen zwei unterschiedliche Sortierreihenfolgen: Telefonbuchsortierung und Wörterbuchsortierung. Bei der Telefonbuchsortierung werden "ä", "ö" etc. so sortiert, als ob es sich um "ae", "oe" etc. handeln würde.

+ +
var names = ['Hochberg', 'Hönigswald', 'Holzman'];
+
+var germanPhonebook = new Intl.Collator('de-DE-u-co-phonebk');
+
+// as if sorting ["Hochberg", "Hoenigswald", "Holzman"]:
+console.log(names.sort(germanPhonebook.compare).join(', '));
+// logs "Hochberg, Hönigswald, Holzman"
+
+ +

Bei manchen Beugungsformen wird ein Vokal zu einem Umlaut, daher ist es sinnvoll, Wörterbücher so zu sortieren, dass Vokale und Umlaute gleich sortiert werden. Bei der Sortierung wird dann also "ä" wie "a" und "ö" wie "o" sortiert. Eine Ausnahme stellen Wörter dar, die sich nur im Umlaut unterscheiden. In solchen Fällen wird der Vokal vor dem Umlaut gereiht (z.B. schon vor schön). 

+ +
var germanDictionary = new Intl.Collator('de-DE-u-co-dict');
+
+// as if sorting ["Hochberg", "Honigswald", "Holzman"]:
+console.log(names.sort(germanDictionary.compare).join(', '));
+// logs "Hochberg, Holzman, Hönigswald"
+
+ +

Mehr Informationen über das {{jsxref("Intl")}} API können unter Introducing the JavaScript Internationalization API (in Englisch) nachgelesen werden.

+ +
{{PreviousNext("Web/JavaScript/Guide/Numbers_and_dates", "Web/JavaScript/Guide/Regular_Expressions")}}
diff --git a/files/de/web/javascript/guide/using_promises/index.html b/files/de/web/javascript/guide/using_promises/index.html new file mode 100644 index 0000000000..0aad2a4071 --- /dev/null +++ b/files/de/web/javascript/guide/using_promises/index.html @@ -0,0 +1,341 @@ +--- +title: Promises benutzen +slug: Web/JavaScript/Guide/Using_promises +translation_of: Web/JavaScript/Guide/Using_promises +--- +
{{jsSidebar("JavaScript Guide")}}{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +

Ein {{jsxref("Promise")}} ist ein Objekt, das die finale Beendigung einer asynchronen Operation repräsentiert. Je nachdem, ob die Operation erfolgreich oder fehlerhaft beendet wurde, wird das Promise entsprechend gekennzeichnet.

+ +

Da in den meisten Fällen bereits existierende Promises benutzt werden, wird diese Anleitung zuerst die Benutzung von zurückgegebenen Promises erklären, und dann darauf eingehen, wie diese erzeugt werden.

+ +

Grob gesagt ist ein Promise ein zurückgegebenes Objekt, an welches Callback-Funktionen angehängt werden können, anstatt dass diese einer Funktion übergeben werden.

+ +

Betrachten wir z.B. folgende Funktion createAudioFileAsync(), welche asynchron eine Audio-Datei generiert; an diese werden Audio-Einstellungen sowie zwei Callback-Funktionen übergeben - eine für das erfolgreiche Erzeugen der Audio-Datei, und die andere für auftretende Fehler.

+ +

Ein beispielhafter Code, den createAudioFileAsync() nutzen würde, sieht in etwa so aus:

+ +
function successCallback(result) {
+  console.log("Audio-Datei bereit unter URL: " + result);
+}
+
+function failureCallback(error) {
+  console.error("Fehlerhafte Generierung der Audio-Datei: " + error);
+}
+
+createAudioFileAsync(audioSettings, successCallback, failureCallback);
+
+ +

In modernen Funktionen, welche Promises zurückgeben, kann man die Callbacks stattdessen direkt anhängen:

+ +

Würde createAudioFileAsync() so umgeschrieben, dass es als Rückgabewert ein Promise hätte, wäre die Nutzung davon einfach so:

+ +
createAudioFileAsync(audiosettings).then(successCallback, failureCallback);
+ +

Das ist die Kurzform von:

+ +
const promise = createAudioFileAsync(audioSettings);
+promise.then(successCallback, failureCallback);
+
+ +

Dies nennt man einen asynchronen Funktionsaufruf. Diese Vorgehensweise hat mehrere Vorteile, von denen in diesem Artikel jeder einzeln geschildert wird.

+ +

Garantien

+ +

Anders als bei Callback-Übergabe nach dem alten Verfahren, können Promise-Objekte folgendes sicherstellen:

+ + + +

Allerdings ist der wohl kurzfristigste Nutzen von Promises das Chaining.

+ +

Chaining

+ +

Eine häufige Aufgabenstellung ist der Aufruf von zwei oder mehr asynchronen Funktionen nacheinander in Sequenz, wobei Ergebnisse aus der vorangegangenen Funktion in die folgende Funktion übernommen werden. Dies ist realisierbar mittels einer Promise chain.

+ +

Hier steckt der Zauber drin: Die Funktion .then() gibt stets ein neues Promise-Objekt zurück:

+ +
const promise = doSomething();
+const promise2 = promise.then(successCallback, failureCallback);
+
+ +

oder auch

+ +
const promise2 = doSomething().then(successCallback, failureCallback);
+
+ +

Hierbei repräsentiert promise2 nicht nur den vollständigen Aufruf von doSomething(), sondern auch die Ergebnisse der beiden angehängten Funktionen successCallback oder failureCallback - diese können ebenfalls asynchrone Funktionen sein, die Promises zurückgeben. In diesem Fall werden jegliche Callback-Funktionen, die an promise2 angehängt würden, jeweils auch eingereiht in den jeweiligen Promise-Rückgabewerten von successCallback oder failureCallback.

+ +

Grundsätzlich repräsentiert jedes Promise-Objekt die Vervollständigung eines asynchronen Schritts in der Kette.

+ +

Nach dem alten Verfahren führte das Aneinanderreihen von mehreren asynchronen Operationen zur klassischen Callback pyramid of doom:

+ +
doSomething(function(result) {
+  doSomethingElse(result, function(newResult) {
+    doThirdThing(newResult, function(finalResult) {
+      console.log('Got the final result: ' + finalResult);
+    }, failureCallback);
+  }, failureCallback);
+}, failureCallback);
+
+ +

Mit moderenen Funktionen können diese Callback-Funktionen stattdessen an die zurückgegebenen Promise-Objekte angehängt werden, womit die Promise chain geformt wird:

+ +
doSomething().then(function(result) {
+  return doSomethingElse(result);
+})
+.then(function(newResult) {
+  return doThirdThing(newResult);
+})
+.then(function(finalResult) {
+  console.log('Got the final result: ' + finalResult);
+})
+.catch(failureCallback);
+
+ +

Die Argumente für .then() sind optional, und .catch(failureCallback) ist die Kurzschreibform von .then(null, failureCallback). Dies kann stattdessen auch mit Pfeil-Funktionen ausgedrückt werden:

+ +
doSomething()
+.then(result => doSomethingElse(result))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => {
+  console.log(`Got the final result: ${finalResult}`);
+})
+.catch(failureCallback);
+
+ +

Wichtig: Immer Rückgabewerte angeben; sonst können die Callback das Ergebnis eines vorherigen Promise nicht abfangen.

+ +

Chaining nach einem .catch()

+ +

Es ist auch möglich, nach einem Fehler, sprich .catch(), weiter zu verkettern. Dies ist nützlich um neue Operationen auszuführen, auch nachdem es einen Fehler in der Kette gab.

+ +
new Promise((resolve, reject) => {
+    console.log('Initial');
+
+    resolve();
+})
+.then(() => {
+    throw new Error('Something failed');
+
+    console.log('Do this');
+})
+.catch(() => {
+    console.log('Do that');
+})
+.then(() => {
+    console.log('Do this, no matter what happened before');
+});
+
+ +

Das obige Beispiel hat die nachfolgenden Ausgaben:

+ +
Initial
+Do that
+Do this, no matter what happened before
+
+ +

Zu beachten ist hier, dass der Text "Do this" nicht ausgegeben wird, weil der Fehler "Something failed" einen Abbruch ausgelöst hat.

+ +

Fehlerübertragung

+ +

Schaut man sich weiter oben die Callback pyramid of doom an, wird sichtbar, dass failureCallback dort mehrmals angegeben werden muss, anders als nur einmal beim Beispiel unten:

+ +
doSomething()
+.then(result => doSomethingElse(result))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => console.log(`Got the final result: ${finalResult}`))
+.catch(failureCallback);
+
+ +

Grundsätzlich hält eine Promise chain bei einer Exception an und erlaubt nur noch Zugriffe von .catch()-Handlern. Dies ist modelliert nach der Funktionsweise von synchronem Code:

+ +
try {
+  const result = syncDoSomething();
+  const newResult = syncDoSomethingElse(result);
+  const finalResult = syncDoThirdThing(newResult);
+  console.log(`Got the final result: ${finalResult}`);
+} catch(error) {
+  failureCallback(error);
+}
+
+ +

Diese Symmetrie mit synchronem Code erreichte ihren Höhepunkt in der async/await-Komfortschreibweise in ECMAScript 2017:

+ +
async function foo() {
+  try {
+    const result = await doSomething();
+    const newResult = await doSomethingElse(result);
+    const finalResult = await doThirdThing(newResult);
+    console.log(`Got the final result: ${finalResult}`);
+  } catch(error) {
+    failureCallback(error);
+  }
+}
+
+ +

Diese Schreibweise baut auf Promises auf; so ist doSomething() die selbe Funktion wie vorher. Hier kann man mehr über diese Syntax erfahren.

+ +

Promise-Objekte lösen mit der Callback pyramid of doom ein fundamentales Designproblem, indem sie alle Fehler, auch geworfene Exceptions und Programmierfehler, abfangen. Diese Eigenschaft ist essentiell für die funktionale Komposition von asynchronen Operationen.

+ +

Promise rejection-Events

+ +

Immer, wenn ein Promise abgelehnt ("rejected") wird, wird eines von zwei Events zum globalen Scope (grundsätzlich entweder window, oder, falls in einem Web-Worker gearbeitet wird, der Worker selbst oder ein anderes, Worker-basiertes Interface) geschickt. Diese beiden Events sind:

+ +
+
rejectionHandled
+
Wird bei der Ablehnung eines Promise gesendet, nachdem die Ablehnung von der reject-Funktion des Ausführenden verarbeitet wurde.
+
unhandledRejection
+
Wird bei der Ablehnung eines Promise gesendet, wenn es keinen Rejection-Handler gibt.
+
+ +

In beiden Fällen hat das Event (vom Typ PromiseRejectionEvent) als Member das Attribut promise welches auf das abgelehnte Promise zeigt, sowie ein Attribut reason welches eine Begründung für die Ablehnung des Promise enthält.

+ +

Diese Events bilden ein Fallback für die Fehlerbehandlung bei Promises sowie eine Hilfestellung beim Debugging des eigenen Promise-Managements. Da die Händler im Kontext global sind, werden alle Fehler unabhängig von der Quelle zu ihnen geschickt.

+ +

Ein Fall der besonderen Nützlichkeit: Wenn man Code in Node.js schreibt, kann es oft passieren, dass im Projekt hinzugefügte Module unverarbeitete abgelehnte Promises haben. Diese werden von der Node-Laufzeitumgebung in die Konsole geloggt. Zu Analysezwecken, zur Verarbeitung durch den eigenen Code, oder auch einfach zur Verhinderung von übermäßigem Output, kann man diese abgelehnten Promises einfangen, indem man für das unhandledrejection event einen Handler hinzufügen:

+ +
window.addEventListener('unhandledrejection', event => {
+  /* Hier lässt sich Code einfügen, um die Attribute des Events
+     zu untersuchen */
+  event.preventDefault();
+}, false);
+ +

Indem die preventDefault()-Methode des Events aufgerufen wird, wird die standardmäßige Operation bei unverarbeiteten abgelehnten Promises verhindert. Üblicherweise beinhaltet dies das Loggen des Fehlers in der Konsole; im Fall von Node ist das tatsächlich der Fall.

+ +

Idealerweise sollte man abgelehnte Promises immer untersuchen, um sicher zu gehen, dass es sich nicht um Code-Fehler handelt.

+ +

Ein Promise-Objekt in einer alten Callback-API erzeugen

+ +

Ein einfaches {{jsxref("Promise")}} kann durch dessen Konstruktor-Methode erzeugt werden. Diese Art und Weise sollte nur genutzt werden, um alte APIs damit zu umschließen.

+ +

Idealerweise würden alle asynchronen Funktionen bereits Promises zurückgeben. In der Realität erwarten einige APIs immer Callback-Funktionen für Erfolg und Fehlerfall, die nach dem alten Prinzip übergeben werden müssen. Ein eindeutiges Beispiel hierfür ist die Funktion {{domxref("WindowTimers.setTimeout", "setTimeout()")}}:

+ +
setTimeout(() => saySomething("10 seconds passed"), 10000);
+
+ +

Callback-Funktionen nach dem alten Verfahren und Promises zu vermischen, bringt Probleme mit sich. Wenn saySomething() fehlschlägt oder Programmierfehler enthält, wird dies durch nichts abgefangen.

+ +

Glücklicherweise kann man solche Fälle mit einem Promise umschließen. Ein Best Practice besteht darin, problematische Funktionen auf der niedrigstmöglichen Ebene zu umschließen, und sie nie wieder direkt aufzurufen:

+ +
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
+
+wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
+
+ +

Der Promise-Konstruktor empfängt grundsätzlich eine Ausführenden-Funktion, die es möglich macht, ein Promise manuell aufzulösen oder abzulehnen. Da setTimeout() nicht wirklich fehlschlägt, wurde im oberen Beispiel die Ablehnung ausgelassen.

+ +

Komposition

+ +

{{jsxref("Promise.resolve()")}} und {{jsxref("Promise.reject()")}} sind Abkürzungen für das manuelle Erzeugen von jeweils bereits aufgelösten oder abgelehnten Promises. In bestimmten Fällen kann dies nützlich sein.

+ +

{{jsxref("Promise.all()")}} und {{jsxref("Promise.race()")}} sind zwei Kompositionswerkzeuge für das parallele Durchführen von asynchronen Operationen.

+ +

Sequenzielle Komposition ist möglich durch cleveres Javascript:

+ +
[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());
+ +

Im oberen Beispiel wird ein Array von asynchronen Funktionen auf eine Promise chain reduziert. Somit ist es das gleiche, wie Promise.resolve().then(func1).then(func2);.

+ +

Auch ist es möglich, dies mit einer wiederverwendbaren Kompositionsfunktion umzusetzen, die häufig in der funktionalen Programmierung vorkommt:

+ +
const applyAsync = (acc,val) => acc.then(val);
+const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
+ +

Die Funktion composeAsync() akzeptiert eine dynamische Anzahl von Funktionen als Parameter, und hat als Rückgabewert eine Funktion, die einen Initialwert akzeptiert, welcher durch die Kompositions-Pipeline durchgereicht wird. Der Nutzen besteht darin, dass einige oder alle übergebenen Funktionen entweder synchron oder asynchron sein können, und garantiert wird, dass sie in der richtigen Reihenfolge ausgeführt werden.

+ +
const transformData = composeAsync(func1, asyncFunc1, asyncFunc2, func2);
+transformData(data);
+
+ +

In ECMAScript 2017 kann sequenzielle Komposition mittels async/await noch einfacher durchgeführt werden:

+ +
for (const f of [func1, func2]) {
+  await f();
+}
+
+ +

Timing

+ +

Um Überraschungen vorzubeugen, werden Funktionen die an .then() übergeben werden niemals synchron aufgerufen, auch wenn das Promise bereits aufgelöst wurde:

+ +
Promise.resolve().then(() => console.log(2));
+console.log(1); // 1, 2
+
+ +

Anstatt sofort ausgeführt zu werden, wird die übergebene Funktion in eine Microtask-Warteschlange eingereiht; das bedeutet, sie wird erst ausgeführt, wenn die Warteschlange am ende des aktuellen Durchlaufs des Javascript event loops geleert wird, sprich zeitnah:

+ +
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+wait().then(() => console.log(4));
+Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
+console.log(1); // 1, 2, 3, 4
+
+ +

Nesting

+ +

Einfache Promise chains sollten möglichst flach und ohne Nesting implementiert werden, da Nesting auch das Ergebnis von undurchdachter Komposition sein kann. Siehe auch bei typischen Fehlern.

+ +

Als Nesting wird eine Kontrollstruktur bezeichnet, um den Scope von catch-Statements zu begrenzen. Ein nested catch fängt nur Fehler in seinem Scope und niedriger ab, nicht außerhalb. Korrekt genutzt führt dies zu höherer Präzision in der Fehlerbehandlung:

+ +
doSomethingCritical()
+.then(result => doSomethingOptional(result)
+  .then(optionalResult => doSomethingExtraNice(optionalResult))
+  .catch(e => {})) // Ignorieren, wenn optionale Operation fehlschlägt
+.then(() => moreCriticalStuff())
+.catch(e => console.error("Critical failure: " + e.message));
+ +

Typische Fehler

+ +

In diesem Abschnitt werden übliche Programmierfehler thematisiert, auf die man achten sollte, um Promise chains nicht zu kompromittieren. Im unteren Beispiel wurden drei der am häufigsten vorkommenden Fehler untergebracht:

+ +
eineFunktion().then(function (ergebnis) {
+  eineZweiteFunktion(ergebnis) // Kein Promise-Rückgabewert für innere Chain + unnötiges Nesting
+  .then(neuesErgebnis => eineDritteFunktion(neuesErgebnis));
+}).then(() => eineVierteFunktion());
+// Keine Chain-Terminierung mit einem catch!
+ +

Der erste Programmierfehler ist, dass die Promise chain nicht ordentlich geknüpft wurde. Passieren tut dies, wenn ein neues Promise erzeugt, aber nicht zurückgegeben wird. Das führt dazu, dass die Promise chain reisst, oder aber, dass zwei chains entstehen, die sich in einer Race condition befinden. Im Klartext heisst das, dass eineVierteFunktion() nicht darauf wartet, dass eineZweiteFunktion() oder eineDritteFunktion() abgeschlossen sind, und, wahrscheinlich unbeabsichtigt, parallel mit ihnen ausgeführt wird. Einzelne Promise chains haben zusätzlich eigene Fehlerbehandlungen, was in diesem Fall zu nicht abgefangenen Fehlern führt.

+ +

Der zweite Programmierfehler ist das unnötige Nesting, welches den ersten Fehler mitverursachen kann. Da Nesting auch den Scope der inneren Fehler-Handler begrenzt, kann dies zu nicht abgefangenen Fehlern führen. Eine Variante hiervon ist das Promise-Konstruktor-Antipattern, welches Nesting mit der redundanten Nutzung eines Promise-Konstruktors, um Code, der bereits Promises nutzt, zu umschließen, kombiniert.

+ +

Der dritte Programmierfehler ist, die Terminierung der Promise chain mit einem .catch() wegzulassen. Unterminierte chains führen in den meisten Browsern zu nicht abgefangenen Promise-Ablehnungen.

+ +

Als Faustregel sei genannt, dass Promise chains immer entweder zurückgegeben oder terminiert werden sollen, und neue Promises sofort zurückgegeben werden sollten, um die Hierarchie flach zu halten:

+ +
eineFunktion()
+.then(function(ergebnis) {
+  return eineZweiteFunktion(ergennis);
+})
+.then(neuesErgebnis => eineDritteFunktion(neuesErgebnis))
+.then(() => eineVierteFunktion())
+.catch(fehler => console.error(fehler));
+ +

Zu beachten ist, dass () => x die Kurzschreibform für () => { return x; } ist.

+ +

Im oberen Beispiel steht jetzt eine einzelne, deterministische Promise chain mit ordentlicher Fehlerbehandlung.

+ +

Das Verwenden von async/await adressiert die meisten, wenn nicht alle dieser Fehlerquellen; stattdessen kann dann der typische Fehler entstehen, dass man await-Keyword vergisst.

+ +

Wenn Promises auf Tasks treffen

+ +

In einer Situation, in der es Promises und Tasks (z.B. Events oder Callbacks) gibt, die in einer unvorhergesehenen Reihenfolge ausgeführt werden / feuern können, ist es möglich, sich einen Microtask zunutze zu machen, um den Status von Promises zu prüfen oder diese auszubalancieren, wenn diese unter bestimmten Bedingungen erzeugt werden.

+ +

Für weitere Informationen über Microtasks und das Einreihen einer Funktion als Microtask mittels queueMicrotask(), kann im Microtask-Guide nachlesen.

+ +

Siehe auch

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}

-- cgit v1.2.3-54-g00ecf