Matthias Fulde: Wofür verwendet man welche funktionstypen???

Beitrag lesen

Hallo MB,

du meinst wohl function expression, nicht function execution

Was die beste Art ist, eine Funktion zu definieren, kann man – wenn überhaupt – nur im Einzelfall sagen. Ich finde es auch schwierig, da allgemeine Regeln zu formulieren. Daher nur ein paar Anmerkungen …

Grundsätzlich wäre meine Empfehlung, Pfeilfunktionen (arrow functions) zu verwenden, wenn man keine Bindung für this benötigt. Im Gegensatz zu gewöhnlichen Funktionsobjekten haben Pfeilfunktionen auch kein prototype-Objekt und es steht kein arguments-Objekt zur Verfügung, das ohnehin nicht mehr verwendet werden sollte.

Ich gehe davon aus, dass dieser kleine Overhead von modernen Ausführungsumgebungen wegoptimiert wird, aber trotzdem kann man dann schon an der Definition erkennen, wie bzw. wofür die Funktion nicht verwendet werden wird.

Persönlich finde ich Pfeilfunktionen auch syntaktisch ansprechender, aber das ist wohl Geschmackssache. 😉

const identity = x => x

Eine solche Deklaration mit const hat jedenfalls den Vorteil, dass der Name später nicht mehr unbeabsichtigt überschrieben werden kann.

function identity(x) {
  return x
}

Wenn man es hingegen so als function statement schreibt, ist (so wie bei Variablen die mit var deklariert werden) eine spätere Redeklaration möglich. Das will man aber in aller Regel nicht, denn das macht den Code intransparent. Die erste Variante garantiert dir also, dass im entsprechende Scope die Bindung von Name und Funktion konstant bleibt.

Dazu kommt, dass bei einer gewöhnlichen Funktionsdeklaration die Deklaration gehoisted wird, das heißt, sie wird implizit an den Anfang des jeweiligen Scopes gezogen. Das heißt, man kann die Funktion aufrufen, bevor man sie im Code deklariert hat. Das ist allerdings keine gute Praxis, da es den Code ebenfalls schwer lesbar macht. Solche Konstrukte kann man durch die Verwendung eines Funktionsausdrucks und die Deklaration mit const (oder let) von vorneherein ausschließen.

Das würde dann allerdings auch für den Fall gelten, dass man tatsächlich eine gewöhnliche Funktion mit this-Bindung unabhängig Deklarieren möchte.

const show = function() {
    console.log(this.data.toString())
}

show.call(object)

Also zusammengefasst: Pfeilfunktion wenn möglich, gewöhnliche Funktion wenn nötig, und lieber function expression mit konstanter Variablenbindung als function statement.

Was man bei der Verwendung von Pfeilfunktionen häufig sieht, ist allerdings eine Tendenz dazu, zu viele anonyme Funktionen zu verwenden, wie zum Beispiel bei den von dir angesprochenen Callbacks. Das macht Code manchmal unnötig schwer lesbar.

const ys = xs.map(x => x**2)

versus

const square = x => x**2

const ys = xs.map(square)

Wenn man eine Funktion sinnvoll bennen kann, sollte man es in aller Regel tun. Das macht den Code besser verständlich. Anonyme Funktionsausdrücke würde ich nur verwenden, wenn die Funktion eher nicht noch einmal an anderer Stelle verwendet wird und eine Benennung nicht groß zum Verständnis des Codes beitragen würde.

Die von dir angesprochenen IIFEs (Immediately Invoked Function Expressions) haben heute eigentlich kaum noch sinnvolle Anwendungsfälle. Das wurde vor der Einführung von Modulen und Blockscope-Variablen (const und let) zur Kapselung verwendet, aber für diesen Zweck braucht man das heute nicht mehr.

{
  // Block scope
  const n = 42
}

console.log(n) // ReferenceError

Ein weiterer Anwendungsfall wäre ein async-IIFE in Browsern, die kein globales await unterstützen. Aber inwieweit das noch relevant ist, weiß ich nicht. Ich kann mich jedenfalls nicht daran erinnern, wann ich dieses Konstrukt tatsächlich das letzte Mal wirklich gebraucht habe.

Viele Grüße,

Matthias