var funktionsname = funktion() {} vs funktion funktionsname() {}
Lesezeit: 8 Minuten
Richard Garside
Ich habe vor kurzem damit begonnen, den JavaScript-Code einer anderen Person zu warten. Ich behebe Fehler, füge Funktionen hinzu und versuche auch, den Code aufzuräumen und konsistenter zu machen.
Der vorherige Entwickler hat zwei Möglichkeiten zum Deklarieren von Funktionen verwendet, und ich kann nicht herausfinden, ob es einen Grund dafür gibt oder nicht.
Die zwei Wege sind:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Was sind die Gründe für die Verwendung dieser beiden unterschiedlichen Methoden und was sind die Vor- und Nachteile der beiden? Gibt es irgendetwas, das mit einer Methode getan werden kann, was mit der anderen nicht möglich ist?
Eugen Lazutkin
Zuerst möchte ich Greg korrigieren: function abc(){} ist ebenfalls im Geltungsbereich – der Name abc wird in dem Geltungsbereich definiert, in dem diese Definition angetroffen wird. Beispiel:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Zweitens ist es möglich, beide Stile zu kombinieren:
var xyz = function abc(){};
xyz wird wie gewohnt definiert, abc ist in allen Browsern außer Internet Explorer undefiniert – verlassen Sie sich nicht darauf, dass es definiert ist. Aber es wird in seinem Körper definiert:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Wenn Sie Alias-Funktionen auf allen Browsern verwenden möchten, verwenden Sie diese Art der Erklärung:
function abc(){};
var xyz = abc;
In diesem Fall beides xyz und abc sind Aliase desselben Objekts:
console.log(xyz === abc); // prints "true"
Ein zwingender Grund für die Verwendung des kombinierten Stils ist das “Name”-Attribut von Funktionsobjekten (vom Internet Explorer nicht unterstützt). Grundsätzlich, wenn Sie eine Funktion wie definieren
function abc(){};
console.log(abc.name); // prints "abc"
sein Name wird automatisch zugewiesen. Aber wenn Sie es wie definieren
var abc = function(){};
console.log(abc.name); // prints ""
sein Name ist leer – wir haben eine anonyme Funktion erstellt und sie einer Variablen zugewiesen.
Ein weiterer guter Grund, den kombinierten Stil zu verwenden, besteht darin, einen kurzen internen Namen zu verwenden, um auf sich selbst zu verweisen, während ein langer, nicht widersprüchlicher Name für externe Benutzer bereitgestellt wird:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
Im obigen Beispiel können wir dasselbe mit einem externen Namen machen, aber es wird zu unhandlich (und langsamer).
(Eine andere Möglichkeit, auf sich selbst zu verweisen, ist die Verwendung arguments.calleeder immer noch relativ lang ist und im strikten Modus nicht unterstützt wird.)
Tief im Inneren behandelt JavaScript beide Anweisungen unterschiedlich. Dies ist eine Funktionsdeklaration:
function abc(){}
abc Hier ist überall im aktuellen Geltungsbereich definiert:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Außerdem hob es durch a return Aussage:
// We can call it here
abc(); // Works
return;
function abc(){}
Dies ist ein Funktionsausdruck:
var xyz = function(){};
xyz hier wird ab dem Zuordnungspunkt definiert:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Funktionsdeklaration vs. Funktionsausdruck ist der wahre Grund, warum es einen Unterschied gibt, den Greg demonstriert.
Lustige Tatsache:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Ich persönlich bevorzuge die Deklaration “Funktionsausdruck”, da ich so die Sichtbarkeit steuern kann. Wenn ich die Funktion wie definiere
var abc = function(){};
Ich weiß, dass ich die Funktion lokal definiert habe. Wenn ich die Funktion wie definiere
abc = function(){};
Ich weiß, dass ich es global definiert habe, vorausgesetzt, ich habe es nicht definiert abc irgendwo in der Kette von Zielfernrohren. Dieser Definitionsstil ist auch im Innenbereich belastbar eval(). Während die Definition
function abc(){};
hängt vom Kontext ab und lässt Sie möglicherweise raten, wo es tatsächlich definiert ist, insbesondere im Fall von eval() — Die Antwort lautet: Es kommt auf den Browser an.
var abc = Funktion () {}; console.log (abc.name); // “abc” // ab 2021
– lfx_cool
3. April 2021 um 16:27 Uhr
Anscheinend wurde die JS-Laufzeit intelligenter. Fassen Sie es aber zusammen und: var abc = (() => function(){})(); console.log (abc.name); // nichts
– Eugen Lazutkin
15. April 2021 um 1:17 Uhr
@EugeneLazutkin Sie führen die Funktion aus und versuchen, den Namen des Ergebnisses zu lesen. Entferne das ‘();’ Teil und dein Beispiel wird richtig sein 😉
– ikirachen
7. Oktober 2021 um 16:51 Uhr
@ikirachen Ich verstehe nicht, worauf Sie sich beziehen. Könnten Sie Ihren Vorschlag mit einem kleinen Kontext versehen, damit ich herausfinden kann, wovon Sie sprechen?
– Eugen Lazutkin
11. Oktober 2021 um 14:52 Uhr
@EugeneLazutkin Sie definieren eine Funktion und rufen sie sofort auf (rufen sie auf), auch als IIFE (Immediately Invoked Function Expression) bezeichnet. Dies ist eine Methode zur Implementierung des lexikalischen Bereichs (nichts aus dem IIFE ist außerhalb davon zugänglich). Also der Wert von abc ist nicht die Funktion selbst, sondern der Rückgabewert dieser Funktion. Es ist sinnvoll, dass abc.name leer ist, da abc eine unbenannte Funktion zurückgibt. @ikirachen erwähnte das Entfernen der () denn das ist es, was die Funktion aufruft. Ohne das wird es nur in überflüssige Klammern gepackt.
– Sinjai
16. November 2021 um 23:43 Uhr
Christian C. Salvado
Apropos globaler Kontext, sowohl die var Aussage und a FunctionDeclaration Am Ende wird ein erstellt nicht löschbar -Eigenschaft auf dem globalen Objekt, sondern den Wert von beiden überschrieben werden können.
Der subtile Unterschied zwischen den beiden Möglichkeiten besteht darin, dass, wenn die Variable Instanziierung Der Prozess führt (vor der eigentlichen Codeausführung) alle mit deklarierten Bezeichner aus var wird mit initialisiert undefinedund diejenigen, die von verwendet werden FunctionDeclaration‘s werden ab diesem Moment verfügbar sein, zum Beispiel:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
Die Beauftragung der barFunctionExpression erfolgt bis zur Laufzeit.
Eine globale Eigenschaft, die von a erstellt wurde FunctionDeclaration kann wie ein Variablenwert problemlos überschrieben werden, zB:
function test () {}
test = null;
Ein weiterer offensichtlicher Unterschied zwischen Ihren beiden Beispielen besteht darin, dass die erste Funktion keinen Namen hat, die zweite jedoch, was beim Debuggen (dh beim Untersuchen eines Aufrufstapels) sehr nützlich sein kann.
Über Ihr bearbeitetes erstes Beispiel (foo = function() { alert('hello!'); };), es handelt sich um eine nicht deklarierte Zuweisung, empfehle ich Ihnen dringend, immer die zu verwenden var Stichwort.
Mit einer Aufgabe, ohne die var -Anweisung, wenn der referenzierte Bezeichner nicht in der Bereichskette gefunden wird, wird er zu einem löschbar Eigenschaft des globalen Objekts.
Auch nicht deklarierte Zuweisungen werfen ein ReferenceError auf ECMAScript 5 unter strikter Modus.
Notiz: Diese Antwort wurde aus einer anderen Frage zusammengeführt, in der der größte Zweifel und das Missverständnis des OP darin bestand, dass mit a deklarierte Identifikatoren FunctionDeclarationkonnte nicht überschrieben werden, was nicht der Fall ist.
Peter Mortensen
Die beiden Codeausschnitte, die Sie dort gepostet haben, verhalten sich für fast alle Zwecke gleich.
Der Unterschied im Verhalten besteht jedoch darin, dass bei der ersten Variante (var functionOne = function() {}), kann diese Funktion erst nach diesem Punkt im Code aufgerufen werden.
Bei der zweiten Variante (function functionTwo()) ist die Funktion für Code verfügbar, der oberhalb der Deklaration der Funktion ausgeführt wird.
Denn bei der ersten Variante wird die Funktion der Variablen zugewiesen foo zur Laufzeit. Im zweiten wird die Funktion diesem Bezeichner zugewiesen, foozur Analysezeit.
Weitere technische Informationen
JavaScript hat drei Möglichkeiten, Funktionen zu definieren.
Ihr erster Ausschnitt zeigt a Funktionsausdruck. Dazu gehört die Verwendung der “Funktion”-Operator um eine Funktion zu erstellen – das Ergebnis dieses Operators kann in jeder Variablen- oder Objekteigenschaft gespeichert werden. Der Funktionsausdruck ist auf diese Weise mächtig. Der Funktionsausdruck wird oft als “anonyme Funktion” bezeichnet, da er keinen Namen haben muss,
Ihr zweites Beispiel ist a Funktionsdeklaration. Dies nutzt die Aussage “Funktion”. um eine Funktion zu erstellen. Die Funktion wird zur Analysezeit verfügbar gemacht und kann überall in diesem Bereich aufgerufen werden. Sie können es später immer noch in einer Variablen- oder Objekteigenschaft speichern.
Die dritte Art, eine Funktion zu definieren, ist die „Function()“-Konstruktor, die in Ihrem ursprünglichen Beitrag nicht angezeigt wird. Es wird nicht empfohlen, dies zu verwenden, da es genauso funktioniert wie eval()was seine Probleme hat.
Gemeinschaft
Eine bessere Erklärung für Gregs Antwort
functionTwo();
function functionTwo() {
}
Warum kein Fehler? Uns wurde immer beigebracht, dass Ausdrücke von oben nach unten ausgeführt werden (??)
Weil:
Funktionsdeklarationen und Variablendeklarationen werden immer verschoben (hoisted) vom JavaScript-Interpreter unsichtbar an den Anfang ihres enthaltenden Gültigkeitsbereichs gesetzt. Funktionsparameter und sprachdefinierte Namen sind offensichtlich bereits vorhanden. Ben Kirsche
Dies bedeutet, dass Code wie folgt:
functionOne(); --------------- var functionOne;
| is actually | functionOne();
var functionOne = function(){ | interpreted |-->
}; | like | functionOne = function(){
--------------- };
Beachten Sie, dass der Zuordnungsteil der Deklarationen nicht gehisst wurde. Nur der Name wird gehisst.
Aber im Fall von Funktionsdeklarationen wird auch der gesamte Funktionsrumpf gehisst:
functionTwo(); --------------- function functionTwo() {
| is actually | };
function functionTwo() { | interpreted |-->
} | like | functionTwo();
---------------
9864600cookie-checkvar funktionsname = funktion() {} vs funktion funktionsname() {}yes