aboutsummaryrefslogtreecommitdiff
path: root/files/de/web/javascript/reference/klassen/index.html
blob: 81bec0651aeb3e554e7ac3ebddf3c5ea0d26f326 (plain)
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
---
title: Klassen
slug: Web/JavaScript/Reference/Klassen
tags:
  - ECMAScript 2015
  - JavaScript
  - Klassen
  - Konstruktor
  - Vererbung
translation_of: Web/JavaScript/Reference/Classes
---
<div>{{JsSidebar("Classes")}}</div>

<div>JavaScript Klassen, eingeführt in ECMAScript 2015, sind syntaktischer Zucker für das bestehende, auf Prototypen basierende, Vererbungsmodell von JavaScript. Diese Syntaxerweiterung führt <strong>kein</strong> neues OOP-Modell in die Sprache ein. JS Klassen ermöglichen es, mit klarer und verständlicher Syntax Objekte zu erstellen und Vererbung in Javascript zu realisieren.</div>

<h2 id="Klassendefinition">Klassendefinition</h2>

<p>Klassen sind eigentlich Funktionen. Analog zu Funktionsausdrücken und Funktionsdeklarationen hat die Klassensyntax zwei Komponenten:</p>

<ul>
 <li>Klassenausdrücke und</li>
 <li>Klassendeklarationen.</li>
</ul>

<h3 id="Klassendeklaration">Klassendeklaration</h3>

<p>Eine Möglichkeit, Klassen zu definieren ist eine <em>Klassendeklaration</em>. Diese wird eingeleitet durch das Schlüsselwort <code>class</code>, gefolgt vom Namen der Klasse (hier: "Rectangle").</p>

<pre class="brush: js">class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}</pre>

<h4 id="Hoisting">Hoisting</h4>

<p>Ein wichtiger Unterschied zwischen <em>Klassen-</em> und <em>Funktionsdeklarationen</em> besteht im sogenannten {{Glossary("Hoisting")}}. Funktionsdeklarationen werden an den Anfang des Definitionsbereichs "gehoben", für Klassen gilt dies nicht. Das heißt, um auf eine Klasse zuzugreifen, muss sie zuvor definiert worden sein, sonst führt dies zu einem {{jsxref("ReferenceError")}}:</p>

<pre class="brush: js example-bad">var p = new Polygon(); // ReferenceError

class Polygon {}
</pre>

<h3 id="Klassenausdruck">Klassenausdruck</h3>

<p>Ein <em>Klassenausdruck</em> ist eine weitere Möglichkeit eine Klasse zu definieren. Dabei ist es optional, hinter dem Schlüsselwort <code>class</code> einen Namen anzugeben. Sollte ein Name angegeben werden, so gilt dieser nur innerhalb des Klassenkörpers.</p>

<pre class="brush: js">// unnamed
var Polygon = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

// named
var Polygon = class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
</pre>

<h2 id="Klassenkörper_und_Methodendefinitionen">Klassenkörper und Methodendefinitionen</h2>

<p>Der Körper der Klasse ist innerhalb der beiden geschweiften Klammern <code>{}</code>. Hier werden die Eigenschaften der Klasse definiert, wie Konstruktoren oder Methoden.</p>

<h3 id="Strict_mode">"Strict mode"</h3>

<p>Der Inhalt der Klassendeklaration und des Klassenausdrucks werden im "<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode">strikten Modus</a>" ausgeführt.</p>

<h3 id="Konstruktor">Konstruktor</h3>

<p>Die <a href="https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Klassen/constructor">Konstruktor</a>-Methode ist eine spezielle Methode, um Objekte zu erzeugen und zu initialisieren. Eine Klasse kann nur eine spezielle Methode mit dem Namen "constructor" haben. Sollte es in einer Klasse mehrere "constructor"-Methoden geben, wird ein {{jsxref("SyntaxError")}} geworfen.</p>

<p>In der Konstruktor-Methode kann man mit dem Schlüsselwort "super", den Konstruktor der Elternklasse aufrufen.</p>

<h3 id="Prototype_Methoden">Prototype Methoden</h3>

<p>Siehe auch <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">Methodendefinitionen</a>.</p>

<pre class="brush: js">class Polygon {
  constructor(hoehe, breite) {
    this.hoehe = hoehe;
    this.breite = breite;
  }

  get flaeche() {
    return this.berechneFlaeche();
  }

  berechneFlaeche() {
    return this.hoehe * this.breite;
  }
}

const quadrat = new Polygon(10, 10);

console.log(quadrat.flaeche);</pre>

<h3 id="Statische_Methoden">Statische Methoden</h3>

<p>Das Schlüsselwort <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/static">static</a></code> definiert statische Methoden. Statische Methoden werden ohne Instanzierung einer Klasse aufgerufen und sind über eine erzeugte Instanz nicht aufrufbar. Oft werden in Applikationen statische Methoden für Hilfsfunktionen verwendet.</p>

<pre class="brush: js">class Punkt {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static laenge(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;

        return Math.sqrt(dx*dx + dy*dy);
    }
}

const p1 = new Punkt(5, 5);
const p2 = new Punkt(10, 10);

console.log(Punkt.laenge(p1, p2));</pre>

<h3 id="Boxing_with_prototype_and_static_methods">Boxing with prototype and static methods</h3>

<p>Wird eine statische oder eine prototype-Methode aufgerufen, ohne dass ein Objekt in der Variable "this" liegt (oder mit "this" als Wahrheitswert, Zeichenkette, Nummer, undefiniert oder null), dann wird die Variable "this" im Funktionskörper undefined sein. Autoboxing wird nicht passieren. Das Verhalten wird das gleiche sein, sollte der Code nicht im "strict mode" geschrieben worden sein.</p>

<pre class="brush: js">class Tier {
  sprich() {
    return this;
  }
  static iss() {
    return this;
  }
}

let obj = new Tier();
let sprich = obj.sprich;
sprich(); // undefined

let iss = Tier.iss;
iss(); // undefined</pre>

<p>Falls wir den vorherigen Quelltext mit klassischen funktionsbasierten Klassen schreiben, wird Autoboxing stattfinden. Dies wird auf dem Wert passieren, der für "this" an die Funktion übergeben wurde.</p>

<pre class="brush: js">function Tier() { }

Tier.prototype.sprich = function() {
  return this;
}

Tier.iss = function() {
  return this;
}

let obj = new Tier();
let sprich = obj.sprich;
sprich(); // Globales Objekt

let iss = Tier.iss;
iss(); // Globales Objekt</pre>

<h2 id="Vererbung_mittels_extends">Vererbung mittels <code>extends</code></h2>

<p>Das Schlüsselwort <code><a href="/en-US/docs/Web/JavaScript/Reference/Classes/extends">extends</a></code> wird dafür verwendet, Klassendeklarationen und Klassenausdrücke zu erzeugen, die von einer anderen Klasse ableiten.</p>

<pre class="brush: js">class Tier{
  constructor(name) {
    this.name = name;
  }

  sprich() {
    console.log(this.name + ' macht ein Geräusch.');
  }
}

class Hund extends Tier{
  sprich() {
    console.log(this.name + ' bellt.');
  }
}

var h = new Hund('Wolfi');
h.sprich();
</pre>

<p>Existiert in der Unterklasse ein Konstruktor, muss dieser zuerst super() aufrufen, bevor "this" verwendet werden kann.</p>

<p>Man kann auch traditionelle funktionsbasierte Klassen erweitern:</p>

<pre class="brush: js">function Tier(name) {
  this.name = name;
}
Tier.prototype.sprich = function () {
  console.log(this.name + ' macht ein Geräusch.');
}

class Hund extends Tier {
  sprich() {
    super.sprich();
    console.log(this.name + ' bellt.');
  }
}

var h = new Hund('Wolfi');
h.sprich();</pre>

<p>Klassen können nicht von regulären (nicht konstruierbaren) Objekten erben. Falls von einem regulärem Objekt geerbt werden soll, kann {{jsxref("Object.setPrototypeOf()")}} verwendet werden:</p>

<pre class="brush: js">var Tier = {
  sprich() {
    console.log(this.name + ' macht ein Geräusch.');
  }
};

class Hund {
  constructor(name) {
    this.name = name;
  }
  sprich() {
    console.log(this.name + ' bellt.');
  }
}

Object.setPrototypeOf(Hund.prototype, Tier);

var h = new Hund('Wolfi');
h.sprich();</pre>

<h2 id="Species">Species</h2>

<p>Falls man zum Beispiel in einer selbst erzeugten Klasse <code>MyArray</code> den Konstruktor mit dem Konstruktor der {{jsxref("Array")}} Klasse überschreiben will, kann man dies mittels des species Musters erreichen.</p>

<p>Zum Beispiel, wenn man die {{jsxref("Array.map", "map()")}} Methode aufruft, wird der Default-Konstruktor der Klasse aufgerufen. Will man, dass stattdessen der Konstruktor der Elternklasse benutzt wird, kann man das {{jsxref("Symbol.species")}}-Symbol dafür verwenden:</p>

<pre class="brush: js">class MyArray extends Array {
  // Überschreibt species mit dem Konstruktor der Array-Klasses
  static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x =&gt; x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true</pre>

<h2 id="Elternklasse_Methoden_mit_super_aufrufen">Elternklasse Methoden mit <code>super</code> aufrufen</h2>

<p>Das Schlüsselwort <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super">super</a></code> kann verwendet werden, um Methoden der Elternklassen aufzurufen</p>

<pre class="brush: js">class Katze{
  constructor(name) {
    this.name = name;
  }

  sprich() {
    console.log(this.name + ' macht ein Geräusch.');
  }
}

class Loewe extends Katze {
  sprich() {
    super.sprich();
    console.log(this.name + ' brüllt.');
  }
}</pre>

<h2 id="Mix-ins">Mix-ins</h2>

<p>Abstrakte Subklassen oder <em>mix-ins</em> sind Vorlagen für Klassen. Eine ECMAScript-Klasse kann nur von einer einzigen Klasse ableiten, damit ist beispielsweise mehrfache Vererbung von Helferklassen nicht möglich. Die gewünschte Funktionalität muss von der Elternklasse bereitgestellt werden.</p>

<p>Eine Funktion die als Input eine Elternklasse nimmt und als Output eine davon abgeleitete Subklasse ausgibt, kann verwendet werden, um mix-ins in ECMAScript zu erzeugen:</p>

<pre class="brush: js">var RechnerMixin = Base =&gt; class extends Base {
  rechne() { }
};

var ZufallsGeneratorMixin = Base =&gt; class extends Base {
  generiere() { }
};</pre>

<p>Eine Klasse die ein solches mix-in verwendet kann so erzeugt werden:</p>

<pre class="brush: js">class Foo { }
class Bar extends RechnerMixin(ZufallsGeneratorMixin(Foo)) { }</pre>

<h2 id="Spezifikationen">Spezifikationen</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Spezifikation</th>
   <th scope="col">Status</th>
   <th scope="col">Kommentar</th>
  </tr>
  <tr>
   <td>{{SpecName('ES2015', '#sec-class-definitions', 'Class definitions')}}</td>
   <td>{{Spec2('ES2015')}}</td>
   <td>Ursprüngliche Definition.</td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-class-definitions', 'Class definitions')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td> </td>
  </tr>
 </tbody>
</table>

<h2 id="Browserkompatibilität">Browserkompatibilität</h2>

<p>{{CompatibilityTable}}</p>

<div id="compat-desktop">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Chrome</th>
   <th>Firefox (Gecko)</th>
   <th>Edge</th>
   <th>Internet Explorer</th>
   <th>Opera</th>
   <th>Safari</th>
  </tr>
  <tr>
   <td>Basic support</td>
   <td>{{CompatChrome(42.0)}}<sup>[1]</sup><br>
    {{CompatChrome(49.0)}}</td>
   <td>{{CompatGeckoDesktop(45)}}</td>
   <td>13</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatSafari(9.0)}}</td>
  </tr>
 </tbody>
</table>
</div>

<div id="compat-mobile">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Funktion</th>
   <th>Android</th>
   <th>Firefox Mobile (Gecko)</th>
   <th>IE Mobile</th>
   <th>Opera Mobile</th>
   <th>Safari Mobile</th>
   <th>Chrome für Android</th>
  </tr>
  <tr>
   <td>Basis Unterstützung</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatGeckoMobile(45)}}</td>
   <td>{{CompatUnknown}}</td>
   <td>{{CompatUnknown}}</td>
   <td>9</td>
   <td>{{CompatChrome(42.0)}}<sup>[1]</sup><br>
    {{CompatChrome(49.0)}}</td>
  </tr>
 </tbody>
</table>
</div>

<p>[1] Benötigt den strikten Modus. Der Support im nicht-strikte Modus verbirgt sich hinter der Flag "Experimentelle JavaScript-Funktionen", welche standardmäßig deaktiviert ist.</p>

<h2 id="Siehe_auch">Siehe auch</h2>

<ul>
 <li>{{jsxref("Guide/Funktionen")}}</li>
 <li>{{jsxref("Statements/class")}}</li>
 <li>{{jsxref("Operators/class")}}</li>
 <li>{{jsxref("Operators/super")}}</li>
 <li><a href="https://hacks.mozilla.org/2015/07/es6-in-depth-classes/">Blog post: "ES6 In Depth: Classes"</a></li>
</ul>