diff options
author | Florian Dieminger <me@fiji-flo.de> | 2021-02-11 18:20:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-11 18:20:22 +0100 |
commit | 999e51572c093be901d6c8f942feb76038ae940c (patch) | |
tree | 0b2242d6df50748abf3f11c717211e8bbcf3d45e /files/de/web/javascript/a_re-introduction_to_javascript | |
parent | 747e709ad97c5782af29688f52c8105c08d9a323 (diff) | |
parent | 12b585b8e60a2877ff64dc6dc5ab058c43652f47 (diff) | |
download | translated-content-999e51572c093be901d6c8f942feb76038ae940c.tar.gz translated-content-999e51572c093be901d6c8f942feb76038ae940c.tar.bz2 translated-content-999e51572c093be901d6c8f942feb76038ae940c.zip |
Merge pull request #55 from fiji-flo/unslugging-de
Unslugging de
Diffstat (limited to 'files/de/web/javascript/a_re-introduction_to_javascript')
-rw-r--r-- | files/de/web/javascript/a_re-introduction_to_javascript/index.html | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/files/de/web/javascript/a_re-introduction_to_javascript/index.html b/files/de/web/javascript/a_re-introduction_to_javascript/index.html new file mode 100644 index 0000000000..1f02dce28d --- /dev/null +++ b/files/de/web/javascript/a_re-introduction_to_javascript/index.html @@ -0,0 +1,910 @@ +--- +title: Eine Wiedereinführung in JavaScript +slug: Web/JavaScript/A_re-introduction_to_JavaScript +tags: + - Anleitung + - CodingScripting + - Einleitung + - Guide + - Intermediate + - JavaScript + - Lernen +translation_of: Web/JavaScript/A_re-introduction_to_JavaScript +original_slug: Web/JavaScript/Eine_Wiedereinfuehrung_in_JavaScript +--- +<div>{{jsSidebar}}</div> + +<p>Warum eine "Wieder" - Einführung? Weil {{Glossary("JavaScript")}} als <a class="external" href="http://javascript.crockford.com/javascript.html">die am meisten missverstandene Programmiersprache der Welt</a> bekannt ist. Obwohl die Sprache oft als Spielzeug abgewertet wird, besitzt sie neben ihrer Einfachheit einige mächtige Sprachfunktionen. Heutzutage wird JavaScript in einer Großzahl von wichtigen Anwendungen verwendet, was zeigt, dass Wissen über diese Technologie eine wichtige Eigenschaft für jeden Web- und Mobil-Entwickler ist.</p> + +<p>Es ist sinnvoll mit einem Überblick über die Sprachgeschichte zu beginnen. JavaScript wurde im Jahr 1995 von Brendan Eich entworfen, der Ingenieur bei Netscape war. JavaScript wurde erstmals 1996 mit Netscape 2 veröffentlicht. Ursprünglich hieß die Sprache LiveScript, wurde aber wegen unglücklichen Marketingentscheidung umbenannt, die sich die Popularität der Java-Sprache von Sun Microsystem zunutze machen wollte - obwohl beide wenig gemeinsam hatten. Dies ist seither eine Quelle für Verwirrung.</p> + +<p>Einige Monate später veröffentlichte Microsoft JScript mit dem Internet Explorer 3. Diese war eine weitgehend zu JavaScript kompatibele Sprache. Einige Monate später übergab Netscape JavaScript an <a class="external" href="https://www.ecma-international.org/">Ecma International</a>, einer Europäischen Standardisierungsorganisation, welche noch im selben Jahr die ersten Edition des {{Glossary("ECMAScript")}} Standards veröffentlichten. Der Standard bekam 1999 ein bedeutendes Update mit <a class="external" href="https://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript Edition 3</a> und hält sich seither sehr stabil. Die vierte Edition des Standards wurde aufgrund von politischen Meinungsverschiedenheiten zur Komplexität der Sprache fallen gelassen. Viele Teile der vieren Edition bildeten die Basis der fünften und sechsten Edition des Standards, welche im Dezember 2009 bzw. im Juni 2015 veröffentlicht wurden.</p> + +<div class="note"> +<p>Aus Gründen der Vertrautheit verwenden wir ab hier die Bezeichnung "JavaScript" anstatt "ECMAScript".</p> +</div> + +<p>Anders als viele andere Programmiersprachen, gibt es bei JavaScript kein Konzept für Eingabe und Ausgabe. JavaScript wurde als Skriptsprache in eine Hostumgebung entworfen und es ist die Aufgabe dieser Umgebung Mechanismen für die Kommunikation mit der Außenwelt bereitzustellen. Die hierfür am meisten genutzte Hostumgebung ist der Browser, jedoch findet man Interpreter auch in vielen anderen Anwendungen, zum Beispiel Adobe Acrobat, Photoshop, SVG Bilder, Yahoo! Widget Umgebung, serverseitigen Applikationen wie <a href="https://nodejs.org/">node.js</a>, NoSQL-Datenbanken wie die Open Source-Datenbank <a href="https://couchdb.apache.org/">Apache CouchDB</a>, integrierte Computer, Desktopumgebungen wie <a href="https://www.gnome.org/">GNOME</a> (eine der beliebtesten Desktopumgebungen für GNU/Linux Betriebssysteme) und vielen mehr.</p> + +<h2 id="Überblick">Überblick</h2> + +<p>JavaScript ist eine dynamische Multi-Paradigmen-Sprache mit Typen und Operatoren, Standardobjekten und Methoden. Die Syntax basiert auf den Sprachen Java und C — viele Strukturen aus diesen Sprachen wurden in JavaScript übernommen. JavaScript unterstützt Objektorientierung mit Prototypobjekten statt Klassen (mehr darüber in <a href="/de/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Vererbung mit Prototypen</a> und ES2015 <a href="/de/docs/Web/JavaScript/Reference/Classes">Klassen</a>). JavaScript unterstützt auch funktionale Programmierung — Funktionen sind Objekte, die Funktionen ermöglichen, ausführbaren Code zu speichern und wie jedes andere Objekt weitergegeben zu werden.</p> + +<p>Beginnen wir mit einer Betrachtung der Sprachbausteine. JavaScript Programme manipulieren Werte und jeder Wert ist von einem bestimmten Typ. JavaScript Typen sind:</p> + +<ul> + <li>{{jsxref("Number")}}</li> + <li>{{jsxref("String")}}</li> + <li>{{jsxref("Boolean")}}</li> + <li>{{jsxref("Function")}}</li> + <li>{{jsxref("Object")}}</li> + <li>{{jsxref("Symbol")}} (neu in ES 6)</li> +</ul> + +<p>... und {{jsxref("undefined")}} und {{jsxref("null")}}, die ein wenig speziell sind. Und {{jsxref("Array")}} , die eine besonere Art von Objekt ist. Und {{jsxref("Date")}} <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Date"> </a>und {{jsxref("RegExp")}}, welche man quasi mitgeliefert bekommt. Wenn man genau sein will, sind Funktionen ebenfalls eine spezielle Art von Objekten. Also sieht das Typdiagramm eher so aus:</p> + +<ul> + <li>{{jsxref("Number")}}</li> + <li>{{jsxref("String")}}</li> + <li>{{jsxref("Boolean")}}</li> + <li>{{jsxref("Symbol")}} (neu in ES2015)</li> + <li>{{jsxref("Object")}} + <ul> + <li>{{jsxref("Function")}}</li> + <li>{{jsxref("Array")}}</li> + <li>{{jsxref("Date")}}</li> + <li>{{jsxref("RegExp")}}</li> + </ul> + </li> + <li>{{jsxref("null")}}</li> + <li>{{jsxref("undefined")}}</li> +</ul> + +<p>Zusätzlich gibt es noch einige vordefinierte {{jsxref("Error")}} Typen. Der Einfachheit halber beschränken wir uns im Folgenden erst einmal auf die Typen aus dem ersten Diagramm.</p> + +<h2 id="Numbers">Numbers</h2> + +<p>Numbers sind in JavaScript laut der Spezifikation "doppeltpräzise 64-bit Werte im IEEE 754 Format". Das hat einige interessante Konsequenzen. Es gibt in JavaScript nichts vergleichbares wie Integer, weshalb man vorsichtig mit Arithmetik umgehen muss, wenn man Mathematik wie in C oder Java nutzt.</p> + +<p>Achte auch auf Dinge wie:</p> + +<pre class="brush: js">0.1 + 0.2 == 0.30000000000000004</pre> + +<p>In der Praxis werden Integer-Werte wie 32-Bit-Integer behandelt und einige Implementierungen speichern sie sogar so, bis sie einen Befehl ausführen sollen, der für eine Number, aber nicht für eine 32-Bit Integer gültig ist. Das kann z.B. für Bitoperationen wichtig sein.</p> + +<p>Unterstützt werden die <a href="/de/docs/Web/JavaScript/Reference/Operators#Arithmetische_Operatoren">arithmetischen Standardoperationen</a>, inklusive Addition, Subtraktion, Modulo (oder Rest) Arithmetik und so weiter. Außerdem existiert noch ein Objekt <em>Math</em> für die Anwendung von mathematischen Funktionen und Konstanten, welches oben noch nicht genannt wurde:</p> + +<pre class="brush: js">Math.sin(3.5); +var umfang = 2 * Math.PI * r;</pre> + +<p>Man kann Strings mit der eingebauten {{jsxref("Global_Objects/parseInt", "parseInt()")}} Funktion nach Integer konvertieren. Die Funktion enthält die Basis des Zahlensystems für die Konvertierung als zweiten optionalen Parameter, welcher immer angegeben werden sollte:</p> + +<pre class="brush: js">parseInt("123", 10); // 123 +parseInt("010", 10); // 10 +</pre> + +<p>In älteren Browsern werden Strings, die mit "0" anfangen als Oktalzahlen (Basis 8) interpretiert, seit 2013 ist das aber nicht mehr so. Wenn man sich bei dem Stringformat nicht sicher ist, kann das in den älteren Browsern zu überraschenden Ergebnissen führen:</p> + +<pre class="brush: js">parseInt("010"); // 8 +parseInt("0x10"); // 16</pre> + +<p>Hier sieht man, dass die {{jsxref("Global_Objects/parseInt", "parseInt()")}} Funktion den ersten String als Oktalzahl, wegen der führenden 0, und den zweiten String als Hexadezimalzahl, wegen des führenden "0x", interpretiert. Die Hexadezimalnotation ist immernoch zulässig; nur die Oktalnotation wurde entfernt, weil sie praktisch nicht mehr verwendet wird.</p> + +<p>Um eine Binärzahl in ein Integer zu ändern, verwendet man einfach die Basis 2:</p> + +<pre class="brush: js">parseInt("11", 2); // 3</pre> + +<p>Auf die gleiche Weise lassen sich auch Gleitkommazahlen mit Hilfe der Funktion<a href="/de/docs/Web/JavaScript/Reference/Global_Objects/parseFloat"> </a> {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} konvertieren. Anders als bei der {{jsxref("Global_Objects/parseInt", "parseInt()")}} Funktion nutzt <code>parseFloat()</code> immer die Basis 10.</p> + +<p>Auch der unäre + Operator kann eingesetzt werden, um zu einer Zahl zu konvertieren:</p> + +<pre class="brush: js">+ "42"; // 42 ++ "010"; // 10 ++ "0x10"; // 16</pre> + +<p>Ein spezieller Wert mit der Bezeichnung {{jsxref("NaN")}} (für "Not a Number") wird zurückgegeben, wenn der String keinen numerischen Wert enthält:</p> + +<pre class="brush: js">parseInt("hello", 10); // NaN</pre> + +<p><code>NaN</code> ist gefährlich: Wenn es als Operand in eine mathematische Operation benutzt wird, wird das Ergebnis ebenfalls <code>NaN</code> sein;</p> + +<pre class="brush: js">NaN + 5; // NaN</pre> + +<p>Mit der eingebauten {{jsxref("Global_Objects/isNaN", "isNaN()")}} Funktion kann man auf <code>NaN</code> testen:</p> + +<pre class="brush: js">isNaN(NaN); // true</pre> + +<p>JavaScript kennt außerdem die speziellen Werte {{jsxref("Infinity")}} und <code>-Infinity</code>:</p> + +<pre class="brush: js"> 1 / 0; // Infinity +-1 / 0; // -Infinity</pre> + +<p>Man kann auf <code>Infinity</code>, <code>-Infinity</code> und <code>NaN</code> Werte mit der eingebauten Funktion {{jsxref("Global_Objects/isFinite", "isFinite()")}} testen:</p> + +<pre class="brush: js">isFinite(1 / 0); // false +isFinite(-Infinity); // false +isFinite(NaN); // false</pre> + +<div class="note"> +<p>Die {{jsxref("Global_Objects/parseInt", "parseInt()")}} und {{jsxref("Global_Objects/parseFloat", "parseFloat()")}} Funktionen lesen einen String, bis ein Zeichen erreicht wird, welches für das Zahlensystem unzulässig ist und geben die Zahl bis zu dieser Stelle zurück. Der unäre + Operator konvertiert den String einfach zu <code>NaN</code>, wenn dieser ein unerlaubtes Zeichen enthält. Probiere mal aus, den String "10.2abc" mit jeder der Methoden in der Console zu konvertieren, um die Unterschiede besser zu verstehen.</p> +</div> + +<h2 id="Strings">Strings</h2> + +<p>Strings sind in JavaScript eine Folge von <a href="/de/docs/Web/JavaScript/Guide/Grammar_and_types#String_Literale">Unicode-Zeichen</a>. Das sollte für alle erfreulich sein, die mit Internationalisierung arbeiten. Genauer gesagt sind Strings Folgen von UTF-16 Codeeinheit; jeder Codeeinheit ist durch eine 16-Bit Zahl repräsentiert. Jedes Unicode-Zeichen besteht aus 1 oder 2 Codeeinheiten.</p> + +<p>Für ein einzelnes Zeichen, verwendet man einfach einen String mit einem Zeichen.</p> + +<p>Um die Länge eines Strings (in Codeeinheiten) herauszufinden, nutzt man die <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/String/length">length </a>Eigenschaft:</p> + +<pre class="brush: js">'hello'.length; // 5</pre> + +<p>Da ist die erster Begegnung mit JavaScript Objekten! Haben wir schon erwähnt, dass man auch Strings wie {{jsxref("Object", "Objekte", "", 1)}} verwenden kann? Sie haben auch {{jsxref("String", "Methoden", "#Methoden", 1)}}, um den Strings zu verändern und Informationen zu erhalten.</p> + +<pre class="brush: js">'hello'.charAt(0); // "h" +'hello, world'.replace('hello', 'goodbye'); // "goodbye, world" +'hello'.toUpperCase(); // "HELLO"</pre> + +<h2 id="Andere_Datentypen">Andere Datentypen</h2> + +<p>JavaScript unterscheidet zwischen {{jsxref("null")}}, wobei es sich um einen Wert handelt, der einen "nicht Wert" repräsentiert (und nur über das <code>null</code> Schlüsselwort erreichbar ist) und {{jsxref("undefined")}}, wobei es sich um einen Wert vom Typ <code>undefined</code> handelt, welcher für einen nicht initialisierten Wert steht - also, dass noch kein Wert zugewiesen wurde. Variablen werden später besprochen, aber in JavaScript ist es möglich Variablen zu deklarieren, ohne ihnen eine Wert zuzuweisen. Wenn das gemacht wird ist die Variable vom Typ <code>undefined</code>. <code>undefined</code> ist sogar eine Konstante.</p> + +<p>JavaScript hat einen Boolean Typ mit den möglichen Werten <code>true</code> und <code>false</code> (beide sind Schlüsselwörter). Jeder Wert kann mit den folgenden Regeln zu einem Boolean konvertiert werden:</p> + +<ol> + <li><code>false</code>, <code>0</code>, leere Strings (<code>""</code>), <code>NaN</code>, <code>null</code>, und <code>undefined</code> werden <code>false</code>.</li> + <li>Alle anderen Werte werden <code>true</code>.</li> +</ol> + +<p>Die Konvertierung kann explizit mit der <code>Boolean()</code> Funktion durchgeführt werden:</p> + +<pre class="brush: js">Boolean(''); // false +Boolean(234); // true</pre> + +<p>Das ist jedoch kaum nötig, da JavaScript die Konvertierung automatisch vornimmt, wenn ein Boolean erwartet wird, wie z.B. bei einer <code>if</code>-Anweisung (siehe unten). Aus diesem Grund ist oft von "true Werten" und "false Werten" die Rede, womit Werte gemeint sind, die zu <code>true</code> oder <code>false</code> werden, nachdem sie zu einem Boolean konvertiert wurden. Alternativ können diese Werte auch "truthy" und "falsy" genannt werden.</p> + +<p>Boolesche Operationen wie beispielsweise <code>&&</code> (logisches <em>und</em>), <code>||</code> (logisches <em>oder</em>) und <code>!</code> (logisches <em>nicht</em>) werden ebenfalls unterstützt (siehe unten).</p> + +<h2 id="Variablen">Variablen</h2> + +<p>Neue Variablen werden in JavaScript mit einem der drei Schlüsselwort <code><a href="/de/docs/Web/JavaScript/Reference/Statements/let">let</a></code>, <code><a href="/de/docs/Web/JavaScript/Reference/Statements/const">const</a></code> oder <code><a href="/de/docs/Web/JavaScript/Reference/Statements/var" title="/en/JavaScript/Reference/Statements/var">var</a></code> <a href="/de/docs/Web/JavaScript/Reference/Statements/var"> </a>deklariert.</p> + +<p><code><strong>let</strong></code> erlaubt es Variablen auf Blockebene zu deklarieren. Die deklarierte Variable ist in dem Block gültig, von dem sie umschlossen wird.</p> + +<pre class="brush: js">let a; +let name = "Simon";</pre> + +<p>Im folgenden ist ein Beispiel für den Gültigkeitsbereich einer mit <code><strong>let</strong></code> deklarierten Variablen:</p> + +<pre class="brush: js">// myLetVariable ist hier *nicht* sichtbar + +for (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) { + // myLetVariable ist nur hier sichtbar +} + +// myLetVariable ist hier *nicht* sichtbar +</pre> + +<p><code><strong>const</strong></code> erlaubt es Variablen zu deklarieren, dessen Wert nie wieder geändert wird. Die Variable ist in dem Block sichtbar, von dem sie umschlossen wird.</p> + +<pre class="brush: js">const Pi = 3.14; // Variable Pi wird initialisiert +Pi = 1; // Führt zu einem Fehler, weil konstante (const) Variablen nicht geändert werden können. +</pre> + +<p><code><strong>var</strong></code> ist das gebräuchlichste deklarative Schlüsselwort. Es hat nicht die Restriktionen, die die anderen beiden Schlüsselwörter haben. Das liegt daran, dass das traditionell der einzige Weg war, um eine Variable in JavaScript zu deklarieren. Eine Variable, die mit dem <code><strong>var</strong></code> Schlüsselwort definiert wird, ist in der Funktion, in der sie deklariert wird, erreichbar.</p> + +<pre class="brush: js">var a; +var name = 'Simon';</pre> + +<p>Im folgenden ist ein Beispiel für den Gültigkeitsbereich einer mit <strong><code>var</code></strong> deklarierten Variablen:</p> + +<pre class="brush: js">// myVarVariable *ist* hier sichtbar + +for (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) { +// myVarVariable ist in der ganzen Funktion sichtbar +} + +// myVarVariable *ist* hier sichtbar</pre> + +<p>Deklariert man eine Variable, ohne ihr einen Wert zuzuweisen, ist ihr Typ <code>undefined</code>.</p> + +<p>Ein sehr wichtiger Unterschied zu anderen Programmiersprachen wie Java besteht darin, dass bei JavaScript keine Blöckegültigkeitsbereiche hat, sondern nur Funktionsgültigkeitsbereiche. Wird eine Variable mit dem <code>var</code> Schlüsselwort in einer zusammengesetzten Statement (z.B. if-Anweisung) definiert, so ist diese Variable innerhalb der ganzen Funktion sichtbar. Jedoch ist es ab ECMAScript 2015 mit <a href="/de/docs/Web/JavaScript/Reference/Statements/let">let </a>und <a href="/de/docs/Web/JavaScript/Reference/Statements/const">const</a> Deklarationen möglich, Variablen mit Blocksichtbarkeitsbereich zu erstellen.</p> + +<h2 id="Operatoren">Operatoren</h2> + +<p>JavaScripts numerische Operatoren sind <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> und <code>%</code> welches der Divisionsrestoperator ist (<a href="/de/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Divisionsrest_()">nicht dasselbe wie Modulo</a>). Werte werden mit <code>=</code> zugewiesen und es gibt zusammengesetzte Zuweisungsstatement wie <code>+=</code> und <code>-=</code>. Diese werden als <code>x = x Operator y</code> interpretiert.</p> + +<pre class="brush: js">x += 5 +x = x + 5</pre> + +<p>Zum Inkrementieren und Dekrementieren kann <code>++</code> und <code>--</code> verwendet werden. Diese können als Prefix oder Postfix Operatoren benutzt werden.</p> + +<p>Mit dem <a href="/de/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition">+ Operator</a> ist es auch möglich, Strings zu verbinden:</p> + +<pre class="brush: js">'hello' + ' world'; // "hello world"</pre> + +<p>Addiert man einen String mit einer Zahl (oder einem anderen Wert), wird alles zuerst zu einem String konvertiert. Dies bereitet manchmal Probleme:</p> + +<pre class="brush: js">"3" + 4 + 5; // "345" +3 + 4 + "5"; // "75"</pre> + +<p>Das Addieren eines leeren Strings zu einem Wert ist eine hilfreiche Methode, den Wert in einen String zu konvertieren.</p> + +<p><a href="/de/docs/Web/JavaScript/Reference/Operators/Vergleichsoperatoren" title="en/Core_JavaScript_1.5_Reference/Operators/Comparison_Operators">Vergleiche</a> können in JavaScript mit <code><</code>, <code>></code>, <code><=</code> und <code>>=</code> durchgeführt werden. Dieses funktionieren bei Strings und Zahlen. Gleichheit ist etwas komplizierter. Der Doppelgleichoperator hat einen Typzwang, was zu überraschend Ergebnissen führen kann:</p> + +<pre class="brush: js">123 == "123"; // true +1 == true; // true</pre> + +<p>Um den Typzwang zu vermeiden, benutzt man den Dreifachgleichoperator:</p> + +<pre class="brush: js">123 === "123"; // false +1 === true; // false</pre> + +<p>Des Weiteren gibt es die Operatoren != und !== für das Testen auf Ungleichheit.</p> + +<p>Außerdem gibt es in JavaScript noch <a href="/en/JavaScript/Reference/Operators/Bitwise_Operators" title="en/Core_JavaScript_1.5_Reference/Operators/Bitwise_Operators">bitweise Operationen</a>.</p> + +<h2 id="Kontrollstrukturen">Kontrollstrukturen</h2> + +<p>JavaScript hat eine ähnliche Menge an Kontrollstrukturen wie andere Sprachen aus der C Familie. Bedingte Statements sind durch <code>if</code> und <code>else</code> unterstützt; man kann sie auch verketten:</p> + +<pre class="brush: js">var name = 'kittens'; +if (name == 'puppies') { + name += ' woof'; +} else if (name == 'kittens') { + name += ' neow'; +} else { + name += '!'; +} +name == 'kittens neow'; +</pre> + +<p>JavaScript hat <code>while</code>- und <code>do-while</code>-Schleifen. Die erste ist gut für normale Schleifen. Die zweite ist für Schleifen geeignet, bei denen sichergestellt werden soll, dass der Schleifeninhalt mindestens einmal ausgeführt wird:</p> + +<pre class="brush: js">while (true) { + // Endlosschleife! +} + +var input; +do { + input = get_input(); +} while (inputIsNotValid(input)) +</pre> + +<p>JavaScripts <a href="/de/docs/Web/JavaScript/Reference/Statements/for"><code>for</code>-Schleife</a> ist die selbe wie in C und Java: Die Kontrollinformationen können in einer einzigen Zeile angegeben werden.</p> + +<pre class="brush: js">for (var i = 0; i < 5; i++) { + // Wird 5-Mal ausgeführt +} +</pre> + +<p>JavaScript hat zudem zwei weitere bekannte for Schleifen: <a href="/de/docs/Web/JavaScript/Reference/Statements/for...of"><code>for</code>...<code>of</code></a></p> + +<pre class="brush: js">for (let value of array) { + // Tue etwas mit value +}</pre> + +<p>und <a href="/de/docs/Web/JavaScript/Reference/Statements/for...in"><code>for</code>...<code>in</code></a>:</p> + +<pre class="brush: js">for (let property in object) { + // Tue etwas mit dem objects property +}</pre> + +<p>Die Operatoren <code>&&</code> und <code>||</code> benutzen Kurzschlusslogik, was bedeutet, dass die Ausführung des zweiten Operanden abhängig von dem ersten ist. Dieses ist nützlich für die Überprüfung auf null, bevor auf Objektattribute zugegriffen wird:</p> + +<pre class="brush: js">var name = o && o.getName(); +</pre> + +<p>Oder für das Abfangen von Werten (wenn falsy Werte nicht valide sind):</p> + +<pre class="brush: js">var name = cachedName || (cachedName = getName()); +</pre> + +<p>JavaScript besitzt einen ternären Operator für bedingte Ausdrücke:</p> + +<pre class="brush: js">var allowed = (age > 18) ? 'yes' : 'no'; +</pre> + +<p>Das <code>switch</code> Statement kann führ mehrere Zweige abhängig von einer Zahl oder einem String eingesetzt werden:</p> + +<pre class="brush: js">switch(action) { + case 'draw': + drawIt(); + break; + case 'eat': + eatIt(); + break; + default: + doNothing(); +} +</pre> + +<p>Lässt man das <code>break</code> Statement weg, werden auch der folgezweig ausgeführt. Dieses Verhalten ist selten gewollt — es lohnt sich in solchen Fällen explizite Kommentare hinzuzufügen, um späteres Debugging zu unterstützen:</p> + +<pre class="brush: js">switch(a) { + case 1: // fallthrough + case 2: + eatit(); + break; + default: + donothing(); +} +</pre> + +<p>Die <code>default</code> Klausel ist optional. Wenn gewünscht, können Ausdrücke im <code>switch</code> und im <code>case</code> eingesetzt werden. Der Vergleiche zwischen beiden wird mit dem === Operator durchgeführt:</p> + +<pre class="brush: js">switch(1 + 3) { + case 2 + 2: + yay(); + break; + default: + neverhappens(); +} +</pre> + +<h2 id="Objekte">Objekte</h2> + +<p>JavaScript Objekte setzen sich aus einfachen Name-Wert-Paaren zusammen. Sie sind ähnlich wie:</p> + +<ul> + <li>Dictionaries in Python</li> + <li>Hashes in Perl und Ruby</li> + <li>Hash tables in C und C++</li> + <li>HashMaps in Java</li> + <li>Assoziative Arrays in PHP</li> +</ul> + +<p>Der Fakt, dass diese Datenstruktur so oft eingesetzt wird, zeigt seine Vielseitigkeit. Da alles (reine Kerntypen) in JavaScript ein Objekt ist, beinhaltet jedes JavaScript-Programm natürlich eine große Menge von Suchoperationen in Hashtabellen. Gut, dass diese so schnell sind!</p> + +<p>Der "Name"-Teil ist ein JavaScript String, während als Wert jeder JavaScript Wert in Frage kommt — auch andere Objekte. Dies ermöglicht das Erstellen von beliebig komplexen Datenstrukturen.</p> + +<p>Es gibt zwei grundlegende Möglichkeiten, ein leeres Objekt zu erstellen:</p> + +<pre class="brush: js">var obj = new Object(); +</pre> + +<p>Und:</p> + +<pre class="brush: js">var obj = {}; +</pre> + +<p>Beide sind semantisch äquivalent. Die zweite wird "Objektliteral Syntax" genannt und ist verbreiteter. Diese Syntax ist zudem der Kern des JSON Formates und sollte immer bevorzugt genutzt werden.</p> + +<p>"Objektliteral Syntax" kann eingesetzt werden, um ein umfassendes Objekt zu erstellen:</p> + +<pre class="brush: js">var obj = { + name: "Carrot", + "for": "Max", + details: { + color: "orange", + size: 12 + } +} +</pre> + +<p>Der Zugriff auf Eigenschaften kann verkettet werden:</p> + +<pre class="brush: js">obj.details.color; // orange +obj["details"]["size"]; // 12</pre> + +<p>Das folgende Beispiel erstellt einen Prototyp <code>Person</code> und eine Instanz dieses Prototyps <code>you</code>.</p> + +<pre class="brush: js">function Person(name, age) { + this.name = name; + this.age = age; +} + +// Definiere ein Objekt +var you = new Person('You', 24); +// Wir erstellen eine Person mit dem Namen "You" und dem Alter 24</pre> + +<p><strong>Nach der Erstellung</strong> kann eine Objekteigenschaft über einem von zwei möglichen Wegen erreicht werden:</p> + +<pre class="brush: js">obj.name = "Simon"; +var name = obj.name; +</pre> + +<p>Und...</p> + +<pre class="brush: js">// Klammernotation +obj['name'] = 'Simon'; +var name = obj['name']; +// man kann eine Variable benutzen, um einen Schlüssel zu definieren +var user = prompt('was ist dein Schlüssel?'); +obj[user] = prompt('was ist dein Schlüssel?'); +</pre> + +<p>Beide sind wieder semantisch äquivalent. Die zweite Methode hat den Vorteil, dass der Name der Eigenschaft als String zur Verfügung gestellt wird, was bedeutet, dass dieser zur Laufzeit berechnet werden kann. Jedoch verhindert diese Methode, dass einige JavaScript-Engines "Minifier Optimierungen" durchführen können. Sie kann außerdem eingesetzt werden, um Eigenschaften zu erreichen, die ein <a href="/de/docs/Web/JavaScript/Reference/Lexical_grammar#Schlüsselwörter" title="en/Core_JavaScript_1.5_Reference/Reserved_Words">reservierte Schlüsselwörter</a> als Namen haben:</p> + +<pre class="brush: js">obj.for = "Simon"; // Syntaxfehler, da 'for' ein reserviertes Schlüsselwort ist +obj["for"] = "Simon"; // funktioniert +</pre> + +<div class="note"> +<p>Ab ECMAScript 5 können reservierte Wörter bei Objektliteralen verwendet werden. Das bedeutet, dass keine Anführungszeichen und eckige Klammern mehr nötig sind. <a href="https://es5.github.io/#x7.6.1">Siehe ES5 Spec</a>.</p> +</div> + +<p>Weitere Informationen zu Objekten und Prototypen gibt es im Artikel <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype">Object.prototype</a>. Für eine Erklärung von Objektprototypen und die Objektprototypenkette siehe in den Artikel <a href="/de/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">Vererbung und die Prototypenkette</a>.</p> + +<div class="note"> +<p>Ab ECMAScript 2015 können Schlüssel mit Variablen definiert werden, indem eckige Klammern verwendet werden. <code>{[phoneType]: 12345}</code> ist möglich, statt <code>var userPhone = {}; userPhone[phoneType] = 12345</code> zu verwenden.</p> +</div> + +<h2 id="Arrays">Arrays</h2> + +<p>Arrays sind in JavaScript ein spezieller Typ von Objekten. Sie funktionieren weitgehend wie normale Objekte (numerische Eigenschaften können nur über die <code>[]</code>-Syntax erreicht werden), besitzen jedoch eine zusätzliche Eigenschaft <code>length</code>. Der Wert dieser Eigenschaft ist immer der höchsten Index des Arrays + 1.</p> + +<p>Eine Möglichkeit ein Array zu erstellen ist die folgende:</p> + +<pre class="brush: js">var a = new Array(); +a[0] = 'dog'; +a[1] = 'cat'; +a[2] = 'hen'; +a.length; // 3</pre> + +<p>Eine praktischere Möglichkeit ist die Erstellung über ein Array-Literal.</p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a.length; // 3</pre> + +<p>Zu beachten ist, dass <code>array.length</code> nicht unbedingt der Anzahl der Elemente des Arrays entspricht. Siehe das folgende Beispiel:</p> + +<pre class="brush: js">var a = ['dog', 'cat', 'hen']; +a[100] = 'fox'; +a.length; // 101</pre> + +<p>Zur Erinnerung: Der Wert von <code>length</code> entspricht immer dem höchsten Index + 1.</p> + +<p>Versucht man auf einen nicht-existenten Array-Index zuzugreifen, erhält man <code>undefined</code>:</p> + +<pre class="brush: js">typeof a[90]; // undefined</pre> + +<p>Wenn Sie die obigen Angaben über <code>[]</code> und Länge (<code>array.length</code>) berücksichtigen, können Sie über ein Array iterieren, indem Sie die folgende for-Schleife verwenden:</p> + +<pre class="brush: js">for (var i = 0; i < a.length; i++) { + // Verarbeitung von a[i] +} +</pre> + +<p>ECMAScript (ES2015) empfiehlt die wesentlich kürzer gefasste <a href="/de/docs/Web/JavaScript/Reference/Statements/for...of"><code>for</code>...<code>of</code></a>-Schleife, um über Objekte und Arrays zu iterieren:</p> + +<pre class="brush: js">for (const currentValue of a) { + // Tue etwas mit currentValue +}</pre> + +<p>Man kann auch mit einer <a href="/de/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a> Schleife über ein Array iterieren, wobei diese nicht über die Arrayelemente, sondern die Arrayindizes iteriert. Zudem wird bei einer solchen Schleife auch über Eigenschaften iteriert, die evtl. später in <code>Array.prototype</code> hinzugefügt werden. Deshalb wird diese Methode für Arrays nicht empfohlen.</p> + +<p>In ECMAScript (ES2015) wurde mit <code><a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">forEach()</a></code> eine weitere Schleife zur Iteration über Arrays eingeführt:</p> + +<pre class="brush: js">['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) { + // Verarbeite currentValue oder array[index] +});</pre> + +<p>Das Anhängen eines neuen Elements zu einem Array funktioniert folgendermaßen:</p> + +<pre class="brush: js">a.push(item);</pre> + +<p>Arrays besitzen viele Methoden. <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Array">Hier findet man die Dokumentation für alle Array Methoden</a>.</p> + +<table style="height: 586px; width: 874px;"> + <thead> + <tr> + <th scope="col">Methodenname</th> + <th scope="col">Beschreibung</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>a.toString()</code></td> + <td>Gibt einen String zurück, bei dem <code>toString()</code> jedes Objektes getrennt mit Komma ist.</td> + </tr> + <tr> + <td><code>a.toLocaleString()</code></td> + <td>Gibt einen String zurück, bei dem <code>toLocaleString</code><code>()</code> jedes Objektes getrennt mit Komma ist.</td> + </tr> + <tr> + <td><code>a.concat(item1[, item2[, ...[, itemN]]])</code></td> + <td>Erstellt eine Kopie mit den neu hinzugefügten Elemente.</td> + </tr> + <tr> + <td><code>a.join(sep)</code></td> + <td>Wandelt das Array in einen String um. Die Elemente werden durch <code>sep</code> getrennt.</td> + </tr> + <tr> + <td><code>a.pop()</code></td> + <td>Entfernt das letzte Element und gibt es zurück.</td> + </tr> + <tr> + <td><code>a.push(item1, ..., itemN)</code></td> + <td>Fügt ein oder mehrere Elemente am Ende hinzu.</td> + </tr> + <tr> + <td><code>a.reverse()</code></td> + <td>Kehrt die Reihenfolge des Arrays um.</td> + </tr> + <tr> + <td><code>a.shift()</code></td> + <td>Entfernt das erste Element und gibt es zurück.</td> + </tr> + <tr> + <td><code>a.slice(start, end)</code></td> + <td>Gibt einen Teil eines Arrays zurück.</td> + </tr> + <tr> + <td><code>a.sort([cmpfn])</code></td> + <td>Sortiert das Array. Ein Vergleichsfunktion kann optional angegeben werden.</td> + </tr> + <tr> + <td><code>a.splice(start, delcount[, item1[, ...[, itemN]]])</code></td> + <td>Modifiziert ein Array, indem ein Teil gelöscht und durch mehrere Elemente ersetzt wird.</td> + </tr> + <tr> + <td><code>a.unshift(item1[, item2[, ...[, itemN]]])</code></td> + <td>Fügt Elemente am Anfang des Arrays hinzu.</td> + </tr> + </tbody> +</table> + +<h2 id="Funktionen">Funktionen</h2> + +<p>Neben Objekten gehören Funktionen zu den Kernkomponenten von JavaScript. Die Syntax für eine einfache Funktion könnte kaum einfacher sein:</p> + +<pre class="brush: js">function add(x, y) { + var total = x + y; + return total; +} +</pre> + +<p>Das Beispiel demonstriert eine einfache Funktion. Einer JavaScript-Funktion können 0 oder mehr benannte Parameter übergeben werden. Der Funktionsrumpf kann beliebig viele Anweisungen enthalten und kann seine eigene lokalen Variablen definieren, die nur in der Funktion erreichbar sind. Das <code>return</code> Statement kann dazu benutzt werden, um jederzeit einen Rückgabewert festzulegen und die Funktion zu beenden. Wird kein <code>return</code>-Statement angegeben (oder ein leeres <code>return</code>-Statement ohne Wert), gibt JavaScript <code>undefined</code> zurück.</p> + +<p>Die benannten Parameter sind eher als Richtlinie zu verstehen, weniger als eine Pflichtangabe. Eine Funktion kann also auch ohne Angabe der Parameter aufgerufen werden, wobei die Parameter dann den Wert <code>undefined</code> bekommen.</p> + +<pre class="brush: js">add() //NaN +// Addition mit undefined ist nicht möglich +</pre> + +<p>Mann kann der Funktion auch mehr Parameter übergeben, als erwartet werden:</p> + +<pre class="brush: js">add(2, 3, 4) // 5 +// Addition der ersten beiden Parameter; 4 wird ignoriert +</pre> + +<p>Auf den ersten Blick wirkt das komisch, jedoch haben Funktionen innerhalb des Funktionsrumpfes Zugriff auf eine zusätzliche Variable namens <a href="/de/docs/Web/JavaScript/Reference/Functions/arguments" title="En/Core_JavaScript_1.5_Reference/Functions_and_function_scope/arguments"><code>arguments</code></a>, welche ein arrayähnliches Objekt ist, das alle der Funktion übergebenen Werte enthält. Hier eine überarbeitete <code>add-</code>Funktion, die beliebig viele Parameter verarbeitet:</p> + +<pre class="brush: js">function add() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum; +} + +add(2, 3, 4, 5); // 14 +</pre> + +<p>Das ist jedoch nicht nützlicher als <code>2 + 3 + 4 + 5</code> zu schreiben. Deswegen erstellen wir eine Funktion, welche den Durchschnitt aller Werte in unserem Array berechnet:</p> + +<pre class="brush: js">function avg() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +} + +avg(2, 3, 4, 5); // 3.5</pre> + +<p>Das ist wirklich nützlich, jedoch wirkt es noch ein bisschen lang. Um den Code ein wenig zu reduzieren, kann man den Einsatz des <code>arguments</code>-Arrays durch eine <a href="/de/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest Parameter Syntax</a> ersetzen. Damit können beliebig viele Argumente übergeben werden und der Code bleibt minimal. Der <strong>Rest Parameter Operator</strong> wird in der Funktionsparameterliste mit dem Format <code>...variable</code> geschrieben und enthält alle nicht benannten, der Funktion übergebenen Argumente in der Variable. Zudem kann man die <code>for</code>-Schleife durch eine <code>for...of</code>-Schleife ersetzen, um die Werte in der Variablen direkt verwenden zu können.</p> + +<pre class="brush: js">function avg(...args) { + var sum = 0; + for (let value of args) { + sum += value; + } + return sum / args.length; +} + +avg(2, 3, 4, 5); // 3.5</pre> + +<div class="note"> +<p>Die Variable <code>args</code><strong> </strong>in der oberen Funktion<strong> </strong>enthält alle an die Funktion übergebenen Werte.</p> + +<p>Es ist wichtig zu beachten, dass der Einsatz des <strong>Rest Parameter Operators</strong> in einer Funktionsdeklaration alle Argumente <strong>nach</strong> der Deklaration enthält, jedoch nicht die davor. Z. B. wird bei <code><em>function avg(</em><strong>firstValue</strong><em>, ...args)</em></code> der erste der Funktion übergebene Wert in der Variable <code>firstValue</code> gespeichert und alle folgenden Werte werden in der Variable <code>args</code> gespeichert. Das ist eine sehr nützliche Sprachfunktion, die jedoch ein neues Problem aufwirft. Die Funktion <code>avg()</code> nimmt eine mit Kommata getrennte Liste von Argumenten entgegen — was ist jedoch, wenn man den Durchschnitt eines Arrays haben möchte? Man kann die Funktion folgendermaßen umschreiben:</p> +</div> + +<pre class="brush: js">function avgArray(arr) { + var sum = 0; + for (var i = 0, j = arr.length; i < j; i++) { + sum += arr[i]; + } + return sum / arr.length; +} + +avgArray([2, 3, 4, 5]); // 3.5</pre> + +<p>Es wäre jedoch schöner, wenn man die erste Funktion wiederverwenden könnten. Glücklicherweise ist es bei JavaScript möglich, eine Funktion mit einem Array von Argumenten aufzurufen, indem man die Methode <code>apply()</code> benutzt, die alle <code>Function</code>-Objekte besitzen:</p> + +<pre class="brush: js">avg.apply(null, [2, 3, 4, 5]); // 3.5</pre> + +<p>Das zweite Argument der <code>apply()</code>-Funktion ist das Array mit den Argumenten; das erste Argument wird später bzw. weiter unten näher erklärt. Das betont noch einmal die Tatsache, dass Funktionen auch Objekte sind.</p> + +<div class="note"> +<p>Man kann das gleiche Ergebnis mit dem Einsatz des <a href="/de/docs/Web/JavaScript/Reference/Operators/Spread_operator">Spread operator</a> im Funktionsaufruf erreichen.</p> + +<p>Zum Beispiel: <code>avg(...numbers);</code></p> +</div> + +<p>JavaScript erlaubt es, anonyme Funktionen zu erstellen:</p> + +<pre class="brush: js">var avg = function() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +} +</pre> + +<p>Die Semantik ist äquivalent zu <code>function avg()</code> Form. Es ist extrem mächtig, weil es erlaubt, an bestimmten Stellen vollständige Funktionsdefinition zu schreiben, wo normalerweise ein Ausdruck verwendet wird. Das ermöglicht allerlei klevere Tricks. Hier eine Möglichkeit, eine Variable zu verbergen — wie Variablen mit Blocksichtbarkeit in C:</p> + +<pre class="brush: js">var a = 1; +var b = 2; + +(function() { + var b = 3; + a += b; +})(); + +a; // 4 +b; // 2</pre> + +<p>JavaScript erlaubt den rekursiven Aufruf von Funktionen. Das ist praktisch beim Verarbeiten von Baumstrukturen, wie es beim Browser-<a href="/en/DOM" title="en/DOM">DOM</a> der Fall ist.</p> + +<pre class="brush: js">function countChars(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += countChars(child); + } + return count; +} +</pre> + +<p>Das hebt ein potentielles Problem mit anonymen Funktionen hervor: Wie ruft man sie rekursiv auf, wenn sie keinen Namen haben? JavaScript erlaubt hierfür die Benennung von Funktionsausdrücken. Man kann dazu benannte "IIFEs" (Immediately Invoked Function Expressions) wie unten beschrieben benutzen:</p> + +<pre class="brush: js">var charsInBody = (function counter(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += counter(child); + } + return count; +})(document.body); +</pre> + +<p>Der angegebene Name im Funktionsausdruck ist nur innerhalb der selben Funktion verfügbar. Das erlaubt der JavaScript-Engine, den Code besser zu optimieren und fördert die Lesbarkeit des Codes. Der Name wird zudem im Debugger und einigen Stack Traces angezeigt, was beim Debuggen viel Zeit sparen kann.</p> + +<p>Zu beachten ist auch hier wieder, dass JavaScript-Funktionen ebenfalls Objekte sind — wie alles andere in JavaScript. Und man kann Eigenschaften ändern und hinzufügen, wie es im oberen Abschnitt über Objekte bereits gezeigt wurde.</p> + +<h2 id="Benutzerdefinierte_Objekte">Benutzerdefinierte Objekte</h2> + +<div class="note">Detaillierte Informationen zum objektorientiertem Programmieren in JavaScript finden Sie in der <a href="/de/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript" title="https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript">Einführung zu objektorientiertem Programmieren in JavaScript</a>.</div> + +<p>In klassischen objektorientierten Programmiersprachen sind Objekte Zusammenstellungen von Daten und Methoden, die mit den Daten arbeiten. JavaScript ist eine Prototypenbasierte Sprache, die anders als in Java oder C++ kein Klassen-Statement besitzt (was manchmal verwirrend für Programmierer ist, die bisher nur mit Sprachen mit Klassen-Statements gearbeitet haben). Stattdessen benutzt JavaScript Funktionen als Klassen. Angenommen es gibt ein Objekt <code><em>person</em></code> mit Feldern für Vor- und Nachnamen. Es gibt zwei Wege den Namen zu schreiben: als "Vorname Nachname" oder "Nachname, Vorname". Nutzt man die vorher beschriebenen Funktionen und Objekte, lässt sich dies z. B. so umsetzen:</p> + +<pre class="brush: js">function makePerson(first, last) { + return { + first: first, + last: last + }; +} +function personFullName(person) { + return person.first + ' ' + person.last; +} +function personFullNameReversed(person) { + return person.last + ', ' + person.first; +} + +s = makePerson("Simon", "Willison"); +personFullName(s); // "Simon Willison" +personFullNameReversed(s); // "Willison, Simon"</pre> + +<p>Das funktioniert zwar, ist aber keine schöne Lösung. Man hat am Ende dutzende unnötiger Funktionen im globalen Namensraum. Was man braucht ist die Möglichkeit, eine Funktion an ein Objekt anzuhängen. Weil Funktionen Objekte sind, lässt sich dies einfach realisieren:</p> + +<pre class="brush: js">function makePerson(first, last) { + return { + first: first, + last: last, + fullName: function() { + return this.first + ' ' + this.last; + }, + fullNameReversed: function() { + return this.last + ', ' + this.first; + } + }; +} + +s = makePerson("Simon", "Willison") +s.fullName(); // "Simon Willison" +s.fullNameReversed(); // "Willison, Simon"</pre> + +<p>Hier sehen Sie etwas, was vorher noch nicht eingesetzt wurde: Das <code><a href="/de/docs/Web/JavaScript/Reference/Operators/this">this</a></code>-Schlüsselwort. Wird es innerhalb einer Funktion benutzt, verweist <code>this</code> auf das aktuelle Objekt. Was das tatsächlich bedeutet, hängt davon ab, wie die Funktion aufgerufen wird. Wenn die Funktion mit der <a href="/de/docs/Web/JavaScript/Reference/Operators/Objekt_Initialisierer#Auf_Eigenschaften_zugreifen">Punkt- oder Klammer-Notation</a> auf einem Objekt aufgerufen wird, repräsentiert <code>this</code> dieses Objekt. Wird die Punkt-Notation nicht verwendet, dann verweist <code>this</code> auf das globale Objekt.</p> + +<p>Zu beachten ist, dass <code>this</code> ein häufiger Grund für Fehler ist. Zum Beispiel:</p> + +<pre class="brush: js">s = makePerson("Simon", "Willison"); +var fullName = s.fullName; +fullName(); // undefined undefined</pre> + +<p>Wenn <code>fullName()</code> alleine und ohne den Einsatz von <code>s.fullName()</code> aufgerufen wird, referenziert <code>this</code> das globale Objekt. Dort gibt es keine globalen Variablen <code>first</code> oder <code>last</code>, weshalb man als Rückgabewert <code>undefined</code> erhält.</p> + +<p>Man kann Vorteile des <code>this</code>-Schlüsselwortes nutzen, um die <code>makePerson</code>-Funktion zu optimieren:</p> + +<pre class="brush: js">function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = function() { + return this.first + ' ' + this.last; + } + this.fullNameReversed = function() { + return this.last + ', ' + this.first; + } +} +var s = new Person("Simon", "Willison"); +</pre> + +<p>Hier wird ein neues Schlüsselwort aufgeführt: <code><code><a href="/de/docs/Web/JavaScript/Reference/Operators/new" title="en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/new_Operator">new</a></code></code>. <code>new</code> steht in starker Beziehung zu <code>this</code>. Es erstellt ein neues Objekt und ruft die nachstehende Funktion auf, wobei <code>this</code> dann das neue Objekt ist. Zu beachten ist, dass die Funktion keinen Wert zurückgibt, sondern das <code>this</code>-Objekt modifiziert. Das <code>new</code> gibt dann das <code>this</code>-Objekt an den Aufrufer zurück. Funktionen die für den Aufruf mit <code>new</code> konzipiert sind, nennt man Konstruktoren. Gängige Praxis ist es, diese Funktionen mit einem großen Anfangsbuchstaben zu versehen, um an den Einsatz von <code>new</code> zu erinnern.</p> + +<p>Die nun optimiertere Funktion hat jedoch immernoch eine Fehlerquelle mit dem Aufruf von<code> fullName()</code>.</p> + +<p>Das <code>person</code>-Objekt wird besser, weist jedoch noch immer einige unangenehme Effekte auf: Bei jedem Erstellen eines <code>person</code>-Objekts werden zwei neue Funktionen erzeugt — wäre es nicht besser, wenn dieser Code wiederverwendet werden könnte?</p> + +<pre class="brush: js">function personFullName() { + return this.first + ' ' + this.last; +} +function personFullNameReversed() { + return this.last + ', ' + this.first; +} +function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = personFullName; + this.fullNameReversed = personFullNameReversed; +} + +</pre> + +<p>Das ist besser: Man erstellt die Methodenfunktionen nur einmal und referenziert zu diesen im Konstruktor. Geht das noch besser? Die Antwort ist auch hier wieder ja:</p> + +<pre class="brush: js">function Person(first, last) { + this.first = first; + this.last = last; +} +Person.prototype.fullName = function() { + return this.first + ' ' + this.last; +} +Person.prototype.fullNameReversed = function() { + return this.last + ', ' + this.first; +}</pre> + +<p><code>Person.prototype</code> ist ein Objekt, das sich alle <code>Person</code>-Instanzen teilen. Dies ist ein Teil einer Prototypen-Suchkette (mit dem speziellen Namen Prototypenkette (prototype chain)): Bei jedem Versuch, auf eine Eigenschaft von <code>Person</code> zuzugreifen, die nicht gesetzt ist, prüft JavaScript ob diese Eigenschaft stattdessen in <code>Person.prototype</code> vorhanden ist. Als Ergebnis wird alles in <code>Person.prototype</code> für alle Instanzen eines Konstruktors über <code>this</code> verfügbar.</p> + +<p>Das ist ein unglaublich mächtiges Werkzeug. JavaScript erlaubt es Prototypen irgendwo innerhalb des Programmes zu verändern, was bedeutet, dass man Methoden zur Laufzeit zu existierenden Objekten hinzufügen kann:</p> + +<pre class="brush: js">s = new Person("Simon", "Willison"); +s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function + +Person.prototype.firstNameCaps = function firstNameCaps() { + return this.first.toUpperCase() +}; +s.firstNameCaps(); // "SIMON"</pre> + +<p>Interessanterweise können auch neue Eigenschaften zu Prototypen von JavaScript-Objekten hinzugefügt werden. So kann z. B. dem <code>String</code>-Objekt eine neue Methode hinzugefügt werden, welche den <code>String</code> in umgekehrter Reihenfolge zurückgibt:</p> + +<pre class="brush: js">var s = "Simon"; +s.reversed(); // TypeError on line 1: s.reversed is not a function + +String.prototype.reversed = function reversed() { + var r = ""; + for (var i = this.length - 1; i >= 0; i--) { + r += this[i]; + } + return r; +}; + +s.reversed(); // nomiS</pre> + +<p>Die neue Methode funktioniert sogar mit String-Literalen!</p> + +<pre class="brush: js">"This can now be reversed".reversed(); // desrever eb won nac sihT</pre> + +<p>Wie schon vorher erwähnt, ist der Prototyp ein Teil einer Kette. Der Anfang dieser Kette ist <code>Object.prototype</code>, welcher die Methode <code>toString()</code> enthält — das ist die Methode die aufgerufen wird, wenn ein Objekt als <code>String</code> repräsentiert werden soll. Das ist für das Debuggen des <code>Person</code>-Objekts nützlich:</p> + +<pre class="brush: js">var s = new Person("Simon", "Willison"); +s; // [object Object] + +Person.prototype.toString = function() { + return '<Person: ' + this.fullName() + '>'; +}; + +s.toString(); // "<Person: Simon Willison>"</pre> + +<p>Erinnern Sie sich an die Stelle weiter oben, als <code>avg.apply()</code> als erstes Argument <code>null</code> übergeben bekommen hat? Diese Stelle können wir uns zur genaueren Betrachtung wieder heranziehen. Mit diesem ersten übergebenen Argument von <code>apply()</code> wird das Objekt festgelegt, welches <code>this</code> repräsentiert. Hier ist z. B. eine einfache Implementierung von <code>new</code>:</p> + +<pre class="brush: js">function trivialNew(constructor, ...args) { + var o = {}; // Create an object + constructor.apply(o, args); + return o; +}</pre> + +<p>Das ist keine exakte Replikation von <code>new</code>, weil die Prototypenkette nicht angelegt wird (es wäre schwer, hier vollständig darzustellen). Das ist nichts, was man häufig benötigt, jedoch ist es nützlich darüber Bescheid zu wissen. In diesem Codeteil nennt man <code>...args</code> (mit den Punkten) das sogenannte <a href="/de/docs/Web/JavaScript/Reference/Functions/rest_parameters">Restargument</a> — wie der Name impliziert, enthält dieser alle restlichen Argumente.</p> + +<p>Der Aufruf von</p> + +<pre class="brush: js">var bill = trivialNew(Person, "William", "Orange");</pre> + +<p>ist somit fast äquivalent zu</p> + +<pre class="brush: js">var bill = new Person("William", "Orange");</pre> + +<p><code>apply()</code> hat eine Schwesterfunktion namens <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Function/call" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Function/call"><code>call</code></a>, die ebenfalls das Setzen von <code>this</code> erlaubt, jedoch statt eines Arrays nimmt sie eine erweiterte Liste mit Argumenten entgegen.</p> + +<pre class="brush: js">function lastNameCaps() { + return this.last.toUpperCase(); +} +var s = new Person("Simon", "Willison"); +lastNameCaps.call(s); +// Das gleiche wie: +s.lastNameCaps = lastNameCaps; +s.lastNameCaps();</pre> + +<h3 id="Innere_Funktionen">Innere Funktionen</h3> + +<p>Funktionsdeklarationen sind in JavaScript auch innerhalb von Funktionen erlaubt. Das lies sich bei der weiter oben verwendeten <code>makePerson()</code>-Funktion schon erkennen. Ein wichtige Eigenschaft von verschachtelten Funktionen in JavaScript ist der Zugriff auf Variablen aus der Elternfunktion:</p> + +<pre class="brush: js">function betterExampleNeeded() { + var a = 1; + function oneMoreThanA() { + return a + 1; + } + return oneMoreThanA(); +} +</pre> + +<p>Dies bietet einen großen Nutzen beim Schreiben von einfacher wartbarem Code. Wenn eine Funktion ein oder zwei andere Funktionen benutzt, diese aber im Code nirgendwo anders benötigt werden, kann man diese Hilfsfunktionen in die Funktion schachteln, die diese schlussendlich eigentlich aufruft. Das hällt die Anzahl der globalen Funktionen niedrig, was immer gut ist.</p> + +<p>Dieses ist ein Gegenpool zum oft verlockenden Einsatz von globalen Variablen. Wenn komplexer Code geschrieben wird, ist es oft verlockend und einfach, globale Variablen für das Teilen von Werten zwischen mehreren Funktionen zu benutzen — was aber zu einem unwartbaren Code führen kann. Geschachtelte Funktionen teilen sich Variablen aus der Elternfunktion, weshalb dieser Mechanismus gut für das Koppeln von Funktionen geeignet ist, wenn es Sinn ergibt, ohne dabei den globalen Namensraum zu verunreinigen — "lokal global" wenn man so will. Diese Technik sollte mit Vorsicht eingesetzt werden, ist jedoch eine nützliche Möglichkeit.</p> + +<h2 id="Closures">Closures</h2> + +<p>Nun wird einer der mächtigsten Abstraktionsmechanismen vorgestellt, den JavaScript mit sich bringt — der jedoch oft auch für Verwirrung sorgt. Was passiert im nachfolgenden Codeschnipsel?</p> + +<pre class="brush: js">function makeAdder(a) { + return function(b) { + return a + b; + }; +} +var x = makeAdder(5); +var y = makeAdder(20); +x(6); // ? +y(7); // ?</pre> + +<p>Der Name der <code>makeAdder</code>-Funktion lässt es schon vermuten, was diese bewirken soll: sie erstellt neue <code>adder</code>-Funktionen, welche dann mit einem Argument aufgerufen werden, welches zu dem Argument addiert wird, mit dem sie erstellt wurden.</p> + +<p>Was hier passiert ist das gleiche wie das, was vorab mit den inneren Funktionen geschehen ist: eine Funktion, die in einer anderen Funktion definiert ist, hat Zugriff auf die Variable der äußeren Funktion. Hier jedoch mit dem Unterschied, dass die äußere Funktion etwas zurückgibt und vortäuscht, dass die lokalen Variablen nicht mehr existieren. Doch bleiben diese bestehen — andernfalls könnte die <code>adder</code>-Funktion nicht funktionieren. Außerdem gibt es zwei verschiedene Kopien der lokalen Variablen der <code>makeAdder()</code>-Funktion — eine, wo <code>a</code> den Wert 5 hat und eine wo <code>a</code> den Wert 20 hat. Die Ergebnisse der beiden Funktionsaufrufe ist deswegen folgendes:</p> + +<pre class="brush: js">x(6) // ergibt 11 +y(7) // ergibt 27 +</pre> + +<p>Hier ist, was tatsächlich passiert. Immer, wenn JavaScript eine Funktion ausführt, wird ein <strong>Scopeobjekt</strong> erstellt, welches die lokalen Variablen enthält, die in der Funktion erstellt werden. Es wird mit jeder Variablen initialisiert, die als Funktionsparameter übergeben wird. Das ist wie mit dem globalen Objekt, welches alle globalen Variablen und Funktionen in sich vorhält, jedoch mit einigen wichtigen Unterschieden: erstens wird immer ein neues Scopeobjekt für jeden Aufruf einer Funktion erstellt und zweitens (anders als bei globalen Objekten, welche als <code>this</code> und in Browsern als <code>window</code> erreichbar sind), sind diese Scopeobjekte nicht direkt im JavaScript Code erreichbar. Es gibt zum Beispiel keinen Mechanismus zum Iterieren aller Eigenschaften eines Scopeobjekts.</p> + +<p>Beim Aufruf der <code>makeAdder()</code>-Funktion wird ein Scope-Objekt erstellt, das eine Eigenschaft besitzt: <code>a</code>, welche das übergebene Argument der <code>makeAdder()</code> Funktion ist. <code>makeAdder()</code> gibt dann eine neu erstellte Funktion zurück. Normalerweise würde der Garbage Collector von JavaScript das für <code>makeAdder()</code> erstellte Scopeobjekt an dieser Stelle entsorgen, doch die zurückgegebene Funktion enthält noch immer eine Referenz auf das Scopeobjekt. Als Resultat wird das Scopeobjekt nicht entsorgt, bis es keine Referenzen mehr auf die von <code>makeAdder()</code> zurückgegebene Funktion gibt.</p> + +<p>Scopeobjekte bilden eine Scopekette, die ähnlich funktioniert wie die Prototypenkette von JavaScripts Objektsystem.</p> + +<p>Eine <strong>Closure</strong> ist eine Kombination aus einer Funktion und dem Scopeobjekt, in dem die Funktion erstellt wurde. Closures sind in der Lage, einen Status zu speichern — als solches können sie oft an Stellen von Objekten eingesetzt werden. <a href="https://stackoverflow.com/questions/111102/how-do-javascript-closures-work">Hier sind einige gute Einführungen zu Closures zu finden</a>.</p> |