Wir haben zwei verschiedene Möglichkeiten, um Funktionsausdrücke in JavaScript auszuführen:
Benannter Funktionsausdruck (NFE) :
var boo = function boo () {
alert(1);
};
Anonymer Funktionsausdruck :
var boo = function () {
alert(1);
};
Und beide können mit angerufen werden boo();
. Ich kann wirklich nicht verstehen, warum / wann ich anonyme Funktionen verwenden sollte und wann ich benannte Funktionsausdrücke verwenden sollte. Welchen Unterschied gibt es zwischen ihnen?
javascript
function
anonymous-function
function-expression
Afshin Mehrabani
quelle
quelle
Antworten:
Im Fall des anonymen Funktionsausdrucks ist die Funktion anonym - buchstäblich hat sie keinen Namen. Die Variable, der Sie sie zuweisen, hat einen Namen, die Funktion jedoch nicht. (Update: Das war durch ES5 der Fall. Ab ES2015 [auch bekannt als ES6] erhält eine mit einem anonymen Ausdruck erstellte Funktion häufig einen wahren Namen [aber keine automatische Kennung], lesen Sie weiter ...)
Namen sind nützlich. Namen können in Stapelspuren, Aufrufstapeln, Listen von Haltepunkten usw. angezeigt werden. Namen sind eine gute Sache ™.
(Früher mussten Sie sich in älteren Versionen von IE [IE8 und darunter] vor benannten Funktionsausdrücken hüten, da diese fälschlicherweise zwei vollständig getrennte Funktionsobjekte zu zwei völlig unterschiedlichen Zeiten erstellt haben [mehr in meinem Blog-Artikel Double take ]. Wenn nötig Unterstützung IE8 [!!], ist es wahrscheinlich am besten mit anonymen Funktion Ausdrücke oder Funktion halten Erklärungen , aber vermeiden sie Funktion Ausdrücke genannt.)
Eine wichtige Sache bei einem benannten Funktionsausdruck ist, dass er einen In-Scope-Bezeichner mit diesem Namen für die Funktion innerhalb des Funktionskörpers erstellt:
Ab ES2015 erstellen jedoch viele "anonyme" Funktionsausdrücke Funktionen mit Namen, und dies wurde von verschiedenen modernen JavaScript-Engines vorweggenommen, die ziemlich klug darin waren, Namen aus dem Kontext abzuleiten. In ES2015 führt Ihr anonymer Funktionsausdruck zu einer Funktion mit dem Namen
boo
. Selbst mit ES2015 + -Semantik wird die automatische Kennung jedoch nicht erstellt:Die Zuweisung des Funktionsnamens erfolgt mit der abstrakten Operation SetFunctionName, die in verschiedenen Operationen in der Spezifikation verwendet wird.
Die Kurzversion ist im Grunde immer dann, wenn ein anonymer Funktionsausdruck auf der rechten Seite von etwas wie einer Zuweisung oder Initialisierung erscheint, wie:
(oder es könnte sein
let
oderconst
eher alsvar
) oderoder
(Die letzten beiden sind wirklich dasselbe) , die resultierende Funktion hat einen Namen (
boo
in den Beispielen).Es gibt eine wichtige und absichtliche Ausnahme: Zuweisen einer Eigenschaft zu einem vorhandenen Objekt:
Dies war auf Bedenken hinsichtlich Informationslecks zurückzuführen, die beim Hinzufügen der neuen Funktion aufgetreten waren. Details in meiner Antwort auf eine andere Frage hier .
quelle
new
Operator verwendet werden sollen (die Angabe aller dieser Funktionsnamen macht die.constructor
Eigenschaft beim Debuggen nützlicher, um herauszufinden, was zum Teufel ist Ein Objekt ist eine Instanz von) und für Funktionsliterale, die direkt an eine Funktion übergeben werden, ohne zuvor einer Eigenschaft oder Variablen (zsetTimeout(function () {/*do stuff*/});
. B. ) zugewiesen zu werden . Sogar Chrome zeigt diese an, es(anonymous function)
sei denn, Sie helfen mit, indem Sie sie benennen.setTimeout
Beispiel den Namen nicht aus dem formalen Argument übernommen hätte, für dassetTimeout
es deklariert wurde , wenn es einen hatte. :-) Aber ja, NFEs sind definitiv nützlich, wenn Sie wissen, dass Sie nicht mit alten Browsern zu tun haben, die einen Hash daraus machen.Benennungsfunktionen sind nützlich, wenn sie sich selbst referenzieren müssen (z. B. für rekursive Aufrufe). Wenn Sie einen Literalfunktionsausdruck als Argument direkt an eine andere Funktion übergeben, kann dieser Funktionsausdruck im strengen ES5-Modus nur dann direkt auf sich selbst verweisen, wenn er benannt ist.
Betrachten Sie beispielsweise diesen Code:
Es wäre unmöglich, diesen Code so sauber zu schreiben, wenn der übergebene Funktionsausdruck
setTimeout
anonym wäre. Wir müssten es stattdessen vor demsetTimeout
Aufruf einer Variablen zuweisen . Auf diese Weise ist ein benannter Funktionsausdruck etwas kürzer und übersichtlicher.Es war historisch möglich, Code wie diesen sogar mit einem anonymen Funktionsausdruck zu schreiben, indem
arguments.callee
...... ist aber
arguments.callee
veraltet und im strengen ES5-Modus völlig verboten. Daher rät MDN:(Hervorhebung von mir)
quelle
Wenn eine Funktion als Funktionsausdruck angegeben ist, kann ihr ein Name zugewiesen werden.
Es ist nur innerhalb der Funktion verfügbar (außer IE8-).
Dieser Name ist für einen zuverlässigen rekursiven Funktionsaufruf vorgesehen, auch wenn er in eine andere Variable geschrieben wird.
Darüber hinaus kann der NFE-Name (Named Function Expression) mit der folgenden
Object.defineProperty(...)
Methode überschrieben werden:Hinweis: Mit der Funktionsdeklaration ist dies nicht möglich. Dieser "spezielle" interne Funktionsname wird nur in der Syntax des Funktionsausdrucks angegeben.
quelle
Sie sollten immer benannte Funktionsausdrücke verwenden, deshalb:
Sie können den Namen dieser Funktion verwenden, wenn Sie eine Rekursion benötigen.
Anonyme Funktionen helfen beim Debuggen nicht, da der Name der Funktion, die Probleme verursacht, nicht angezeigt wird.
Wenn Sie eine Funktion nicht benennen, ist es später schwieriger zu verstehen, was sie tut. Wenn Sie ihm einen Namen geben, ist das Verständnis einfacher.
Da hier beispielsweise die Namensleiste in einem Funktionsausdruck verwendet wird, wird sie im äußeren Bereich nicht deklariert. Bei benannten Funktionsausdrücken wird der Name des Funktionsausdrucks in einen eigenen Bereich eingeschlossen.
quelle
Die Verwendung benannter Funktionsausdrücke ist besser, wenn Sie auf die betreffende Funktion verweisen möchten, ohne sich auf veraltete Funktionen wie z
arguments.callee
.quelle