IIFE in vier Schritten
IIFEs waren eine häufig anzutreffende Technik im ES5-Standard, denn sie verschafften Variablen einen »Block Scope«, einen eingeschränkten Gültigkeitsbereich, verhinderten die Überflutung des globalen Scopes und geben den Speicher schnell wieder frei.
Der Name hört sich kompliziert an, die Schwemme der Klammerpaare wirkt schon wie eine Abschirmung. Dabei sind die Selbstausführenden Funktionen und ihre Vorteile einfach zu verstehen.
Schritt 1: Eine einfache Funktion
function foo () { // script code }
Schritt 1 ist eine ganz normale einfache Javascript-Funktion.
Schritt 2: Namenslos – nicht ohne Weiteres
function () { // script code }
Eine Funktion ohne Namen würde zu einem Fehler führen, weil der Name fehlt: Uncaught SyntaxError: Function statements require a function name.
Schritt 3: Eingeklammert
(function () { // script code })
Setzen wir Klammern rund um die Funktion, erkennt Javascript darin einen Ausdruck oder Funktionsausdruck (function expression). Die Funktion bleibt im Speicher, aber wird nie aufgerufen.
Schritt 4: Der Aufruf der Funktion
Deklaration Aufruf ┌───────┴──────┐ ┌┐ | | || ▼ ▼ ▼▼ (function () {}) ();
Das leere Klammernpaar macht's: Das ist der Aufruf der Funktion, die jetzt direkt ausgeführt wird.
Abschirmen
Sofort ausgeführte Funktionen erzeugen eine Abschirmung, unter der die Funktionen und Variablen nach außen – also global – nicht sichtbar sind. Das war in der Zeit vor ES5 und den Variablenvereinbarungen mit let und const besonders wichtig.
Es gibt zwei Schreibweisen, beide mit einer Inflation von runden Klammern:
(function(){ let test = true; })();
(function() { let test = true; } () );
Für die Fans der Arrow-Funktion:
(() => { //script code })()
Variablen und Funktionen innerhalb von IIFE können außerhalb der IIFE nicht angesprochen werden, sie sind sozusagen privates Eigentum der selbst ausführenden Funktionen. Denken wir nur einmal daran, wie viele Scripte eine Funktion init nennen!
(function IIFE_slideshow () { let slides; let position; function init() { console.log ("iife " ); } init(); })();
ES6 erzeugt einen Block Scope – den geschränkten Gültigkeitsbereich – einfach durch geschweifte Klammern. Das erspart die Klammerorgie der IFFEs – jedenfalls, wenn wir sicher sind, das externe Script nur let und const für die Deklaration von Variablen verwenden und die Finger von var-Deklarationen lassen.
{ const slides = ["bild1.jpg", "bild2.jpg", "bild3.jpg"]; let position; const init = () => console.log ("IIFE sagt Hallo!"); … }
Schutz der Variablen
Die Variable test ist außerhalb der Funktion nicht sichtbar. So kommt es zwischen den Scripten innerhalb einer Seite nicht zu Interferenzen, selbst wenn sie dieselben Variablennamen und Namen für private Funktionen benutzen.
Sofort ausführbare Funktionen werden direkt an Ort und Stelle ausgeführt, so als wären sie eine einzelne Anweisung. Wenn die Funktion abgearbeitet ist, sind alle Variablen der Funktion vergessen. Das hält den Namensraum sauber und räumt den Speicher frei.
Selbst-ausführende Funktionen verfolgen ein ähnliches Konzept wie anonyme Funktionen.
var foo = function() { /* Anweisungen */ }
oder – ein bekanntes Muster –
document.getElementById('foo').onclick = function () { /* Anweisungen */ }
Anonyme Funktionen werden beim Aufruf einer Variablen zugewiesen, so dass sie nicht wirklich anonym sind. Immediately Invoked Function Expressions oder Self Executing Functions brauchen ein paar Klammern mehr – erst dann sind sie wirklich anonym.
Wieso die vielen Klammern?
Die Deklaration einer Funktion – function foo() {} – ist kein ausführbarer Ausdruck. Erst der Aufruf mit dem Namen gefolgt von runden Klammern erzeugt den ausführbaren Ausdruck: foo().
Um eine anonyme Funktion direkt an Ort und Stelle auszuführen, muss der Parser erkennen, dass er einen Ausdruck vor sich hat und keine Deklaration einer Funktion. Eine Form der Notation sind die runden Klammern rund um die Funktion – in Javascript können Ausdrücke nicht in Klammern sitzen.
(function() { /* Anweisungen */ }) ();
oder so
const iifeArrow = (() => { console.log ("array-function as iife") })()
setTimeout in Self Executing Function
Wird ein String als Argument übergeben, versucht Javascript diesen String zu evaluieren, wenn der Timeout feuert. Das wäre im globalen Bereich, in dem die Methode nicht existiert.
setTimeout ("changeImg()", time);
Stattdessen
setTimeout (changeImg, time);
Minimale Slideshow mit Vanilla Javascript
(function () { let i = 0; let images = []; let time = 3000; images [0] = "bird1.png"; images [1] = "bird2.png"; images [2] = "bird3.png"; function changeImg () { document.querySelector(".slide").src = images[i]; if ( i < images.length - 1) { i++; } else { i = 0; } setTimeout (changeImg, time); } window.onload = changeImg; })();
Verkürzte Schreibweise
Wenn man sich nicht um einen Return Value kümmern muss und es unrelevant ist, dass der Code etwas schwerer lesbar wird, kann man ein Byte sparen, indem man einen Unary Operator-Präfix vor die Funktion setzt.
!function(){ /* Anweisungen */ }();
Das ist ein vertrautes Muster: So beginnen Libraries wie jQuery und viele andere kleine Helfer.
/* Smooth Scroll with ankers*/ !function(e,t){"function"==typeof define&&define.amd?define([] /*! jQuery v1.12.0 | (c) jQuery Foundation | jquery.org/license */ !function(a,b){"object"==typeof module&&"object"==t
IIFE mit Return-Wert
IIFEs können einen Namen haben und auch einen Return-Wert abliefern.
let result = (function IIFE_slideshow () { let slides; let position; function init() { console.log ("iife " ); } init(); return "Grüße von IIFE"; })(); console.log (result);