1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
|
---
title: Eine Wiedereinführung in JavaScript
slug: Web/JavaScript/Eine_Wiedereinfuehrung_in_JavaScript
tags:
- Anleitung
- CodingScripting
- Einleitung
- Guide
- Intermediate
- JavaScript
- Lernen
translation_of: Web/JavaScript/A_re-introduction_to_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>
|