We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

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.

Syntax

Basis Syntax

(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 }

Fortgeschrittene Syntax

// 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

Beschreibung

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.

Kürzere Funktionen

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]

Keine Bindung von 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 non-strict mode, definiert die growUp() Funktion `this` 
    // als das globale Objekt, das sich jenem `this` unterscheidet, 
    // welches vom Person() Konstruktor definiert wurde.
    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();

Zusammenhang mit dem Strict Mode

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.

Aufruf durch call oder apply

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

Keine Bindung von Argumenten

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

Pfeilfunktionen als Methoden

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 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
  }
});

Verwendung des new Operators

Pfeilfunktionen 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

Einsatz der prototype Eigenschaft

Pfeilfunktionen haben keine prototype Eigenschaft.

var Foo = () => {};
console.log(Foo.prototype); // undefined

Verwendung des Schlüsselwortes yield

Das yield-Schlüsselwort sollte im Rumpf 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.

Funktionsrumpf

Pfeilfunktionen können entweder einen "knappen" oder einen gewöhnlichen "Block-Rumpf" haben.

In einem knappen Rumpf ist lediglich ein Ausdruck nötig und eine implizite Rückgabe wird angehängt. In einem Block-Rumpf 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 Block-Rumpf, explizite Rückgabe wird benötigt

Rückgabe von Objekt-Literalen

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 });

Zeilenumbruch

Pfeilfunktionen können keinen Zeilenumbruch zwischen Parametern und dem Pfeil haben.

var func = ()
           => 1; 
// SyntaxError: Ausdruck erwartet, '=>' erhalten

Übersetzungsreihenfolge

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

Weitere Beispiele

// 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);

Spezifikationen

Spezifikation Status Kommentar
ECMAScript 2015 (6th Edition, ECMA-262)
Die Definition von 'Arrow Function Definitions' in dieser Spezifikation.
Standard Initiale Definition.
ECMAScript Latest Draft (ECMA-262)
Die Definition von 'Arrow Function Definitions' in dieser Spezifikation.
Entwurf  

Browserkompatibilität

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Grundlegende Unterstützung45 Ja221 2 Nein3210
Trailing comma in parameters58 ?52 Nein45 ?
FeatureAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
Grundlegende Unterstützung4545 Ja221 232105.0
Trailing comma in parameters5858 ?5245 ?7.0

1. The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of 'use strict'; is now required.

2. Prior to Firefox 39, a line terminator (\n) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like () \n => {} will now throw a SyntaxError in this and later versions.

Siehe auch

Schlagwörter des Dokuments und Mitwirkende

Mitwirkende an dieser Seite: Sixl-Daniel, schlagi123, kdex, sja, Eiknheimer, GuidoSchweizer, mhash17
Zuletzt aktualisiert von: Sixl-Daniel,