--- title: Pfeilfunktionen slug: Web/JavaScript/Reference/Functions/Pfeilfunktionen tags: - ECMAScript 2015 - Functions - Intermediate - JavaScript - Reference translation_of: Web/JavaScript/Reference/Functions/Arrow_functions ---
Der Ausdruck einer Pfeilfunktion hat eine kürzere Syntax als ein Funktionsausdruck und hat kein eigenes this
, arguments, super, oder new.target. Solche Funktionsausdrücke sind am besten für Funktionen, die nicht als Methode genutzt werden, geeignet und können nicht als Konstruktoren verwendet werden.
(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 }
// Der Body kann eingeklammert werden, um ein Objektliteral Ausdruck zurück zu geben: params => ({foo: bar}) // Rest Parameter und Default Parameter werden unterstützt (param1, param2, ...rest) => { statements } (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } // Destrukturierung in der Parameterliste ist ebenfalls unterstützt var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6
Siehe auch "ES6 In Depth: Arrow functions" on hacks.mozilla.org.
Zwei Faktoren haben die Einführung von Pfeilfunktionen beeinflusst: kürzere Funktionen und dass this
nicht gebunden ist.
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]
this
Vor (der Einführung von) Pfeilfunktionen definierte jede Funktion ihren eigenen this
-Wert (d.h. ein neues Objekt im Falle eines Konstruktors; in strict mode 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.
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();
In ECMAScript 3/5 konnte dies durch Zuweisung des Wertes von this
an eine Variable, welche umschlossen werden konnte, behoben werden.
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); }
Alternativ könnte eine gebundene Funktion erstellt werden, sodass der passende this
-Wert an die growUp()
-Funktion übergeben würde.
Eine Pfeilfunktion erstellt keinen eigenen this
Kontext, wodurch this
die ursprüngliche Bedeutung des umschließenden Kontextes trägt. Somit funktioniert der folgende Code wie erwartet.
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| bezieht sich entsprechend auf das Person-Objekt }, 1000); } var p = new Person();
Vorausgesetzt, dass this
aus dem umschließenden lexikalischen Kontext kommt, werden Strict Mode Regeln bezüglich this
einfach ignoriert.
var f = () => {'use strict'; return this}; f() === window; // oder das globale Objekt
Die restlichen strict mode Regeln verhalten sich normal.
Da this
in Pfeilfunktionen nicht gebunden ist, können call()
oder apply()
Methoden nur Argumente übergeben; this
wird ignoriert:
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
Pfeilfunktionen haben kein eigenes arguments
Objekt. Somit ist arguments
einfach eine Referenz auf den Namen innerhalb des umschließenden Geltungsbereichs (scope).
var arguments = [1, 2, 3]; var arr = () => arguments[0]; arr(); // 1 function foo(n) { var f = () => arguments[0] + n; // implizite Argumenten-Bindung von foo return f(); } foo(1); // 2
In den meisten Fällen sind Rest Parameters eine gute Alternative zum Einsatz des arguments
Objektes:
function foo(n) { var f = (...args) => args[0] + n; return f(10); } foo(1); // 11
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.
'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
Pfeilfunktionen definieren (binden sozusagen) kein eigenes this
. Ein anderes Beispiel, das {{jsxref("Object.defineProperty()")}} betrifft:
'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 } });
new
OperatorsPfeilfunktionen können nicht als Konstruktoren verwendet werden. Sie führen zu einem Fehler, wenn auf ihnen ein new
angewendet wird.
var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor
prototype
EigenschaftPfeilfunktionen haben keine prototype
Eigenschaft.
var Foo = () => {}; console.log(Foo.prototype); // undefined
yield
Das yield
-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.
Pfeilfunktionen können entweder einen "knappen" oder einen gewöhnlichen "Blockkörper" haben.
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.
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
Man bedenke, dass die Rückgabe von Objekt-Literalen unter Verwendung der knappen Syntax params => {object:literal}
nicht so ausgeführt wird, wie man es erwarten würde:
var func = () => { foo: 1 }; // Der Aufruf von func() gibt undefined zurück! var func = () => { foo: function() {} }; // SyntaxError: function-Anweisung erfordert einen Namen
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).
Man bedenke, das Objekt-Literal in Klammern zu setzen:
var func = () => ({ foo: 1 });
Pfeilfunktionen können keinen Zeilenumbruch zwischen Parametern und dem Pfeil haben.
var func = () => 1; // SyntaxError: Ausdruck erwartet, '=>' erhalten
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 (operator precedence) anders interagieren.
let callback; callback = callback || function() {}; // ok callback = callback || () => {}; // SyntaxError: invalid arrow-function arguments callback = callback || (() => {}); // ok
// 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);
Spezifikation | Status | Kommentar |
---|---|---|
{{SpecName('ES2015', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ES2015')}} | Initiale Definition. |
{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ESDraft')}} |
{{Compat("javascript.functions.arrow_functions")}}