I've vor kurzem begonnen Wartung jemand anderes ' s JavaScript-Code. Ich behebe Fehler, füge Funktionen hinzu und versuche auch, den Code aufzuräumen und konsistenter zu machen.
Der vorherige Entwickler verwendet zwei Arten der Deklaration von Funktionen und ich kann nicht herausfinden, ob es einen Grund dafür gibt oder nicht.
Die beiden Möglichkeiten 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 jeweiligen Methode? Gibt es etwas, das man mit der einen Methode machen kann, was mit der anderen nicht möglich ist?
Der Unterschied besteht darin, dass FunktionEins
ein Funktionsausdruck ist und daher erst definiert wird, wenn diese Zeile erreicht wird, während FunktionZwei
eine Funktionsdeklaration ist und definiert wird, sobald die sie umgebende Funktion oder das sie umgebende Skript ausgeführt wird (aufgrund von hoisting).
Zum Beispiel, ein Funktionsausdruck:
// TypeError: functionOne is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
Und, eine Funktionsdeklaration:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
Das bedeutet auch, dass Sie keine Funktionen mit Hilfe von Funktionsdeklarationen bedingt definieren können:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
Das obige Beispiel definiert functionThree
unabhängig vom Wert von test
— es sei denn, use strict
ist in Kraft, in welchem Fall es einfach einen Fehler auslöst.
Zuerst möchte ich Greg korrigieren: Funktion abc(){}
ist zu scoped — der Name abc
ist in dem Bereich definiert, in dem diese Definition vorkommt. 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 üblich definiert, abc
ist in allen Browsern außer dem Internet Explorer &mdash nicht definiert; verlassen Sie sich nicht darauf, dass es definiert ist. Aber es wird innerhalb seines Körpers definiert:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Wenn Sie Funktionen in allen Browsern aliasieren wollen, verwenden Sie diese Art von Deklaration:
function abc(){};
var xyz = abc;
In diesem Fall sind sowohl xyz
als auch abc
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 (nicht unterstützt von Internet Explorer). Wenn Sie eine Funktion definieren wie
function abc(){};
console.log(abc.name); // prints "abc"
wird ihr automatisch ein Name zugewiesen. Aber wenn Sie sie definieren wie
var abc = function(){};
console.log(abc.name); // prints ""
ist ihr Name 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, und gleichzeitig einen langen, nicht widersprüchlichen Namen für externe Benutzer bereitzustellen:
// 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önnten wir das Gleiche mit einem externen Namen tun, aber das wäre zu unhandlich (und langsamer).
(Eine andere Möglichkeit, auf sich selbst zu verweisen, ist die Verwendung von arguments.callee
, was aber immer noch relativ lang ist und im strict mode nicht unterstützt wird.)
In der Tiefe behandelt JavaScript beide Anweisungen unterschiedlich. Dies ist eine Funktionsdeklaration:
function abc(){}
abc
ist hier überall im aktuellen Bereich 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 wird es durch eine return
-Anweisung hochgezogen:
// We can call it here
abc(); // Works
return;
function abc(){}
Dies ist ein Funktionsausdruck:
var xyz = function(){};
Hier ist "xyz" vom Punkt der Zuweisung aus 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 eigentliche Grund, warum es einen Unterschied gibt, wie Greg gezeigt hat.
Lustige Tatsache:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Ich persönlich bevorzuge die "Funktionsausdruck"-Deklaration, weil ich auf diese Weise die Sichtbarkeit kontrollieren kann. Wenn ich die Funktion wie folgt definiere
var abc = function(){};
weiß ich, dass ich die Funktion lokal definiert habe. Wenn ich die Funktion wie folgt definiere
abc = function(){};
weiß ich, dass ich sie global definiert habe, vorausgesetzt, dass ich nirgendwo in der Kette der Anwendungsbereiche abc
definiert habe. Diese Art der Definition ist auch dann belastbar, wenn sie innerhalb von eval()
verwendet wird. Während die Definition
function abc(){};
vom Kontext abhängt und Sie vielleicht raten lässt, wo sie tatsächlich definiert ist, besonders im Fall von eval()
— die Antwort ist: Es hängt vom Browser ab.
In der Informatik spricht man von anonymen Funktionen und benannten Funktionen. Ich denke, der wichtigste Unterschied ist, dass eine anonyme Funktion nicht an einen Namen gebunden ist, daher der Name anonyme Funktion. In JavaScript ist sie ein Objekt erster Klasse, das zur Laufzeit dynamisch deklariert wird.
Für weitere Informationen über anonyme Funktionen und Lambda-Kalküle ist Wikipedia ein guter Ausgangspunkt (http://en.wikipedia.org/wiki/Anonymous_function).