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
|
---
title: Pfeilfunktionen
slug: Web/JavaScript/Reference/Functions/Pfeilfunktionen
tags:
- ECMAScript 2015
- Functions
- Intermediate
- JavaScript
- Reference
translation_of: Web/JavaScript/Reference/Functions/Arrow_functions
---
<div>{{jsSidebar("Functions")}}</div>
<p>Der <strong>Ausdruck einer Pfeilfunktion</strong> hat eine kürzere Syntax als ein <a href="/de/docs/Web/JavaScript/Reference/Operators/function">Funktionsausdruck</a> und hat kein eigenes <code><a href="/de/docs/Web/JavaScript/Reference/Operators/this">this</a></code>, <a href="/de/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>, <a href="/de/docs/Web/JavaScript/Reference/Operators/super">super</a>, oder <a href="/de/docs/Web/JavaScript/Reference/Operators/new.target">new.target</a>. Solche Funktionsausdrücke sind am besten für Funktionen, die nicht als Methode genutzt werden, geeignet und können nicht als Konstruktoren verwendet werden.</p>
<div>{{EmbedInteractiveExample("pages/js/functions-arrow.html")}}</div>
<h2 id="Syntax">Syntax</h2>
<h3 id="Basis_Syntax">Basis Syntax</h3>
<pre class="syntaxbox">(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// gleich zu: => { return expression; }
// Klammern sind optional, wenn nur ein Parametername vorhanden ist:
(singleParam) => { statements }
singleParam => { statements }
// Die Parameterliste für eine parameterlose Funktion muss mit einem Klammernpaar geschrieben werden
() => { statements }
</pre>
<h3 id="Fortgeschrittene_Syntax">Fortgeschrittene Syntax</h3>
<pre class="syntaxbox">// Der Body kann eingeklammert werden, um ein Objektliteral Ausdruck zurück zu geben:
params => ({foo: bar})
// <a href="/de/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest Parameter</a> und <a href="/de/docs/Web/JavaScript/Reference/Functions/Default_parameters">Default Parameter</a> werden unterstützt
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
statements }
// <a href="/de/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">Destrukturierung</a> in der Parameterliste ist ebenfalls unterstützt
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f(); // 6
</pre>
<h2 id="Beschreibung">Beschreibung</h2>
<p>Siehe auch <a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">"ES6 In Depth: Arrow functions" on hacks.mozilla.org</a>.</p>
<p>Zwei Faktoren haben die Einführung von Pfeilfunktionen beeinflusst: kürzere Funktionen und dass <code>this</code> nicht gebunden ist.</p>
<h3 id="Kürzere_Funktionen">Kürzere Funktionen</h3>
<pre class="brush: js">var elements = [
"Hydrogen",
"Helium",
"Lithium",
"Beryllium"
];
elements.map(function(element) {
return element.length
}); // [8, 6, 7, 9]
elements.map(element => {
return element.length
}); // [8, 6, 7, 9]
elements.map(({length}) => length); // [8, 6, 7, 9]</pre>
<h3 id="Keine_Bindung_von_this">Keine Bindung von <code>this</code></h3>
<p>Vor (der Einführung von) Pfeilfunktionen definierte jede Funktion ihren eigenen <code><a href="/de/docs/Web/JavaScript/Reference/Operators/this">this</a></code>-Wert (d.h. ein neues Objekt im Falle eines Konstruktors; in <a href="/de/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a> Funktionsaufrufen nicht definiert; bzw. das kontextuelle Objekt, wenn die Funktion als eine "Objekt-Methode" aufgerufen wurde, usw.). Dies stellte sich innerhalb eines objektorientierten Programmierstils als lästig heraus.</p>
<pre class="brush: js">function Person() {
// Der Person() Konstruktor definiert `this` als Instanz von sich selbst.
this.age = 0;
setInterval(function growUp() {
// Im nicht Strict Modus, definiert die growUp() Funktion `this`
// als das globale Objekt (weil das der Ort ist, an dem growUp() ausgeführt wird),
// das sich von dem `this`, welches vom Person() Konstruktor definiert wurde unterscheidet.
this.age++;
}, 1000);
}
var p = new Person();</pre>
<p>In ECMAScript 3/5 konnte dies durch Zuweisung des Wertes von <code>this</code> an eine Variable, welche umschlossen werden konnte, behoben werden.</p>
<pre class="brush: js">function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// Der Rückruf bezieht sich auf jene `that`-Variable,
// deren Wert das zu erwartende Objekt ist.
that.age++;
}, 1000);
}</pre>
<p>Alternativ könnte eine <a href="/de/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">gebundene Funktion</a> erstellt werden, sodass der passende <code>this</code>-Wert an die <code>growUp()</code>-Funktion übergeben würde.</p>
<p>Eine Pfeilfunktion erstellt keinen eigenen <code>this</code> Kontext, wodurch <code>this</code> die ursprüngliche Bedeutung des umschließenden Kontextes trägt. Somit funktioniert der folgende Code wie erwartet.</p>
<pre class="brush: js">function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| bezieht sich entsprechend auf das Person-Objekt
}, 1000);
}
var p = new Person();</pre>
<h4 id="Zusammenhang_mit_dem_Strict_Mode">Zusammenhang mit dem Strict Mode</h4>
<p>Vorausgesetzt, dass <code>this</code> aus dem umschließenden lexikalischen Kontext kommt, werden <a href="/de/docs/Web/JavaScript/Reference/Strict_mode">Strict Mode</a> Regeln bezüglich <code>this</code> einfach ignoriert.</p>
<pre class="brush: js">var f = () => {'use strict'; return this};
f() === window; // oder das globale Objekt</pre>
<p>Die restlichen strict mode Regeln verhalten sich normal.</p>
<h4 id="Aufruf_durch_call_oder_apply">Aufruf durch call oder apply</h4>
<p>Da <code>this</code><em> </em>in Pfeilfunktionen nicht gebunden ist, können <code>call()</code><em> </em>oder <code>apply()</code> Methoden nur Argumente übergeben; <code>this</code> wird ignoriert:</p>
<pre class="brush: js">var adder = {
base : 1,
add : function(a) {
var f = v => v + this.base;
return f(a);
},
addThruCall: function(a) {
var f = v => v + this.base;
var b = {
base : 2
};
return f.call(b, a);
}
};
console.log(adder.add(1)); // Dies würde 2 ausgeben
console.log(adder.addThruCall(1)); // Dies würde nach wie vor 2 ausgeben</pre>
<h3 id="Keine_Bindung_von_Argumenten">Keine Bindung von Argumenten</h3>
<p>Pfeilfunktionen haben kein eigenes <a href="/de/docs/Web/JavaScript/Reference/Functions/arguments"><code>arguments</code> Objekt</a>. Somit ist <code>arguments</code> einfach eine Referenz auf den Namen innerhalb des umschließenden Geltungsbereichs (scope).</p>
<pre class="brush: js">var arguments = [1, 2, 3];
var arr = () => arguments[0];
arr(); // 1
function foo(n) {
var f = () => arguments[0] + n; // implizite Argumenten-Bindung von <em>foo</em>
return f();
}
foo(1); // 2</pre>
<p>In den meisten Fällen sind <a href="/de/docs/Web/JavaScript/Reference/Functions/rest_parameters">Rest Parameters</a> eine gute Alternative zum Einsatz des <code>arguments</code> Objektes:</p>
<pre class="brush: js">function foo(n) {
var f = (...args) => args[0] + n;
return f(10);
}
foo(1); // 11</pre>
<h3 id="Pfeilfunktionen_als_Methoden">Pfeilfunktionen als Methoden</h3>
<p>Wie angegeben, sind Ausdrücke von Pfeilfunktionen am besten geeignet für nicht-methodische Funktionen. Man sehe, was geschieht, wenn versucht wird, sie als Methoden zu verwenden.</p>
<pre class="brush: js">'use strict';
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // gibt undefined, Window {...} aus (oder das globale Objekt)
obj.c(); // gibt 10, Object {...} aus</pre>
<p>Pfeilfunktionen definieren (binden sozusagen) kein eigenes <code>this</code>. Ein anderes Beispiel, das {{jsxref("Object.defineProperty()")}} betrifft:</p>
<pre class="brush: js">'use strict';
var obj = {
a: 10
};
Object.defineProperty(obj, "b", {
get: () => {
console.log(this.a, typeof this.a, this);
return this.a+10; // stellt das globale Objekt 'Window' dar, 'this.a' gibt daher 'undefined' zurück
}
});
</pre>
<h3 id="Verwendung_des_new_Operators">Verwendung des <code>new</code> Operators</h3>
<p>Pfeilfunktionen können nicht als Konstruktoren verwendet werden. Sie führen zu einem Fehler, wenn auf ihnen ein <code>new</code> angewendet wird.</p>
<pre class="brush: js">var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
</pre>
<h3 id="Einsatz_der_prototype_Eigenschaft">Einsatz der <code>prototype</code> Eigenschaft</h3>
<p>Pfeilfunktionen haben keine <code>prototype</code> Eigenschaft.</p>
<pre class="brush: js">var Foo = () => {};
console.log(Foo.prototype); // undefined
</pre>
<h3 id="Verwendung_des_Schlüsselwortes_yield">Verwendung des Schlüsselwortes <code>yield</code></h3>
<p>Das <code><a href="/de/docs/Web/JavaScript/Reference/Operators/yield">yield</a></code>-Schlüsselwort sollte im Körper einer Pfeilfunktion nicht verwendet werden (außer wenn dies innerhalb von darin weiter verschachtelten Funktionen erlaubt ist). Als Folge können Pfeilfunktionen nicht als Generatoren verwendet werden.</p>
<h2 id="Funktionskörper">Funktionskörper</h2>
<p>Pfeilfunktionen können entweder einen "knappen" oder einen gewöhnlichen "Blockkörper" haben.</p>
<p>In einem knappen Körper ist lediglich ein Ausdruck nötig und eine implizite Rückgabe wird angehängt. In einem Blockkörper muss eine explizite Rückgabe-Anweisung verwendet werden.</p>
<pre class="brush: js">var func = x => x * x;
// knappe Syntax, implizierte Rückgabe
var func = (x, y) => { return x + y; };
// mit Blockkörper, explizite Rückgabe wird benötigt
</pre>
<h2 id="Rückgabe_von_Objekt-Literalen">Rückgabe von Objekt-Literalen</h2>
<p>Man bedenke, dass die Rückgabe von Objekt-Literalen unter Verwendung der knappen Syntax <code>params => {object:literal}</code> nicht so ausgeführt wird, wie man es erwarten würde:</p>
<pre class="brush: js">var func = () => { foo: 1 };
// Der Aufruf von func() gibt undefined zurück!
var func = () => { foo: function() {} };
// SyntaxError: function-Anweisung erfordert einen Namen</pre>
<p>Der Grund dafür ist, dass der Code in geschweiften Klammern ({}) als eine Sequenz von Anweisungen übersetzt wird (d.h. foo wird als Bezeichner behandelt und nicht als Schlüssel eines Objekt-Literals).</p>
<p>Man bedenke, das Objekt-Literal in Klammern zu setzen:</p>
<pre class="brush: js">var func = () => ({ foo: 1 });</pre>
<h2 id="Zeilenumbruch">Zeilenumbruch</h2>
<p>Pfeilfunktionen können keinen Zeilenumbruch zwischen Parametern und dem Pfeil haben.</p>
<pre class="brush: js">var func = ()
=> 1;
// SyntaxError: Ausdruck erwartet, '=>' erhalten</pre>
<h2 id="Übersetzungsreihenfolge">Übersetzungsreihenfolge</h2>
<p>Der Pfeil innerhalb einer Pfeilfunktion ist kein Operator. Allerdings haben Pfeilfunktionen im Vergleich zu gewöhnlichen Funktionen besondere Übersetzungsregeln, welche mit der Priorität von Operatoren (<a href="/de/docs/Web/JavaScript/Reference/Operators/Operator_Precedence">operator precedence</a>) anders interagieren.</p>
<pre class="brush: js">let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() => {}); // ok
</pre>
<h2 id="Weitere_Beispiele">Weitere Beispiele</h2>
<pre class="brush: js">// Eine leere Pfeilfunktion gibt undefined zurück
let empty = () => {};
(() => "foobar")()
// Gibt "foobar" zurück
// (Das ist eine Immediately Invoked Function Expression
// siehe IIFE im Glossar
var simple = a => a > 15 ? 15 : a;
simple(16); // 15
simple(10); // 10
let max = (a, b) => a > b ? a : b;
// Einfaches filtering, mapping, ... von Arrays
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b);
// 66
var even = arr.filter(v => v % 2 == 0);
// [6, 0, 18]
var double = arr.map(v => v * 2);
// [10, 12, 26, 0, 2, 36, 46]
// Weitere knappe Zusicherungsketten (promise chains)
promise.then(a => {
// ...
}).then(b => {
// ...
});
// Parameterlose Pfeilfunktionen, welche visuell einfacher zu verstehen sind
setTimeout( _ => {
console.log("I happen sooner");
setTimeout( _ => {
// deeper code
console.log("I happen later");
}, 1);
}, 1);</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-arrow-function-definitions', 'Arrow Function Definitions')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Initiale Definition.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td> </td>
</tr>
</tbody>
</table>
<h2 id="Browserkompatibilität">Browserkompatibilität</h2>
<div>
<p>{{Compat("javascript.functions.arrow_functions")}}</p>
</div>
<h2 id="Siehe_auch">Siehe auch</h2>
<ul>
<li><a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">"ES6 In Depth: Arrow functions" on hacks.mozilla.org</a></li>
</ul>
|