Es gibt noch eine weitere Möglichkeit, eine Funktion zu erstellen. Es wird selten verwendet, aber manchmal gibt es keine Alternative.
Die Syntax zum Erstellen einer Funktion:
let func = new Function ([arg1, arg2, ...argN], functionBody);
Die Funktion wird mit den Argumenten arg1...argN
und dem angegebenen functionBody
erstellt.
Es ist leichter zu verstehen, wenn man sich ein Beispiel anschaut. Hier ist eine Funktion mit zwei Argumenten:
let sum = new Function('a', 'b', 'return a + b'); alarm( sum(1, 2) ); // 3
Und hier gibt es eine Funktion ohne Argumente, nur mit dem Funktionskörper:
let sayHi = new Function('alert("Hello")'); sayHi(); // Hallo
Der Hauptunterschied zu anderen Methoden, die wir gesehen haben, besteht darin, dass die Funktion buchstäblich aus einer Zeichenfolge erstellt wird, die zur Laufzeit übergeben wird.
Bei allen vorherigen Deklarationen mussten wir Programmierer den Funktionscode in das Skript schreiben.
Mit new Function
kann jedoch jede Zeichenfolge in eine Funktion umgewandelt werden. Beispielsweise können wir eine neue Funktion von einem Server empfangen und diese dann ausführen:
let str = ... den Code dynamisch von einem Server empfangen ... let func = new Function(str); func();
Es wird in ganz bestimmten Fällen verwendet, etwa wenn wir Code von einem Server empfangen oder in komplexen Webanwendungen eine Funktion dynamisch aus einer Vorlage kompilieren.
Normalerweise merkt sich eine Funktion, wo sie in der speziellen Eigenschaft [[Environment]]
erstellt wurde. Es verweist auf die lexikalische Umgebung, in der es erstellt wurde (wir haben das im Kapitel Variablenbereich, Abschluss behandelt).
Wenn jedoch eine Funktion mit new Function
erstellt wird, wird ihre [[Environment]]
so eingestellt, dass sie nicht auf die aktuelle lexikalische Umgebung verweist, sondern auf die globale.
Eine solche Funktion hat also keinen Zugriff auf äußere Variablen, sondern nur auf die globalen.
Funktion getFunc() { let value = "test"; let func = new Function('alert(value)'); Rückgabefunktion; } getFunc()(); // Fehler: Wert ist nicht definiert
Vergleichen Sie es mit dem regulären Verhalten:
Funktion getFunc() { let value = "test"; let func = function() { alarm(value); }; Rückgabefunktion; } getFunc()(); // „test“, aus der lexikalischen Umgebung von getFunc
Diese besondere Funktion der new Function
sieht seltsam aus, scheint aber in der Praxis sehr nützlich zu sein.
Stellen Sie sich vor, wir müssen eine Funktion aus einer Zeichenfolge erstellen. Der Code dieser Funktion ist zum Zeitpunkt des Schreibens des Skripts nicht bekannt (deshalb verwenden wir keine regulären Funktionen), wird aber während des Ausführungsprozesses bekannt sein. Wir können es vom Server oder von einer anderen Quelle erhalten.
Unsere neue Funktion muss mit dem Hauptskript interagieren.
Was wäre, wenn es auf die äußeren Variablen zugreifen könnte?
Das Problem besteht darin, dass JavaScript vor der Veröffentlichung in der Produktion mit einem Minifier komprimiert wird – einem speziellen Programm, das den Code verkleinert, indem es zusätzliche Kommentare und Leerzeichen entfernt und – was wichtig ist – lokale Variablen in kürzere umbenennt.
Wenn eine Funktion beispielsweise let userName
hat, ersetzt der Minifier diese durch let a
(oder einen anderen Buchstaben, falls dieser belegt ist) und führt dies überall aus. Dies ist normalerweise eine sichere Vorgehensweise, da die Variable lokal ist und nichts außerhalb der Funktion darauf zugreifen kann. Und innerhalb der Funktion ersetzt Minifier jede Erwähnung davon. Minifier sind intelligent, sie analysieren die Codestruktur, sodass sie nichts kaputt machen. Sie sind nicht nur ein blödes Suchen und Ersetzen.
Wenn new Function
also Zugriff auf äußere Variablen hätte, wäre sie nicht in der Lage, den umbenannten userName
zu finden.
Wenn new Function
Zugriff auf äußere Variablen hätte, gäbe es Probleme mit Minifiern.
Außerdem wäre ein solcher Code architektonisch schlecht und fehleranfällig.
Um etwas an eine Funktion zu übergeben, die als new Function
erstellt wurde, sollten wir ihre Argumente verwenden.
Die Syntax:
let func = new Function ([arg1, arg2, ...argN], functionBody);
Aus historischen Gründen können Argumente auch als durch Kommas getrennte Liste angegeben werden.
Diese drei Erklärungen bedeuten dasselbe:
new Function('a', 'b', 'return a + b'); // grundlegende Syntax new Function('a,b', 'return a + b'); // durch Kommas getrennt new Function('a , b', 'return a + b'); // Komma-getrennt mit Leerzeichen
Funktionen, die mit new Function
erstellt wurden, haben [[Environment]]
das auf die globale lexikalische Umgebung verweist, nicht auf die äußere. Daher können sie keine äußeren Variablen verwenden. Aber das ist eigentlich gut, denn es schützt uns vor Fehlern. Die explizite Übergabe von Parametern ist architektonisch eine viel bessere Methode und verursacht keine Probleme mit Minifiern.