32 Stimmen

Warum kann ich eine Javascript-Funktion nicht vor ihrer Definition innerhalb eines Try-Blocks verwenden?

Wie erörtert aquí können Funktionsdefinitionen verwendet werden, bevor sie definiert sind. Sobald jedoch ein Codeabschnitt in einen Try-Block eingeschlossen ist, ist dies nicht mehr der Fall.

Dies zeigt "Hallo Welt" an:

hello();
function hello() { alert("Hello world"); }

Es wird jedoch "ReferenceError: hello is not defined" angezeigt:

try {
  hello();
  function hello() { alert("Hello world"); }
} catch (err) {
  alert(err);
}

Ein Try-Block hat also eindeutig etwas "Besonderes" im Hinblick auf Funktionsdeklarationen. Gibt es eine Möglichkeit, dieses Verhalten zu umgehen?

26voto

BGerrissen Punkte 20514

Firefox interpretiert Funktionsanweisungen anders und hat offenbar das Deklarations-Hoisting für die Funktionsdeklaration aufgehoben. ( Eine gute Lektüre über benannte Funktionen / Deklaration vs. Ausdruck )

Der Grund für die unterschiedliche Interpretation der Anweisungen durch Firefox ist der folgende Code:

if ( true ) {
    function test(){alert("YAY");}
} else {
    function test(){alert("FAIL");}
}
test(); // should alert FAIL

Aufgrund der Deklarationserhöhung, Funktion test sollte immer "fail" anzeigen, aber nicht in Firefox. Der obige Code meldet tatsächlich "YAY" in Firefox, und ich vermute, dass der Code, der dafür sorgt, dass das Deklarations-Hoisting schließlich ganz wegfällt.

Ich nehme an, dass Firefox Funktionsdeklarationen in var-Deklarationen umwandelt, wenn sie sich in if/else- oder try/catch-Anweisungen befinden. Zum Beispiel so:

// firefox interpretted code
var test; // hoisted
if (true) {
   test = function(){alert("yay")}
} else {
   test = function(){alert("fail")}
}

Nach einer kurzen Debatte mit Šime Vidas muss ich sagen, dass der Umgang von Firefox mit Funktionsdeklarationen nicht standardisiert ist, weil:

Die Produktion SourceElement : Anweisung wird für Funktion verarbeitet deklarationen durch Nichtstun .
Die Produktion SourceElement : Anweisung wird wie folgt ausgewertet:

  1. Aussage auswerten.
  2. Rückgabe Ergebnis(1).

Sowohl FunctionDeclaration als auch Statement sind SourceElements, ergo sollte es keine FunctionDeclarations innerhalb eines Statements geben (if/else, try/catch). Geben Sie Šime Vidas einen Brownie!

Try/catch ist im Grunde eine andere Form von if/else und verwendet wahrscheinlich denselben Ausnahmecode.

5voto

Chris Noe Punkte 35043

In Anbetracht der Tatsache, dass ein Funktionsblock einen lokalen Bereich mit Vorwärts-Funktionsreferenzierung einrichtet, scheint die Einbettung des Inhalts des try-Blocks in eine unmittelbare Funktion dieses Verhalten wiederherzustellen.

Dies funktioniert in Firefox, IE und Chrome:

try {
  (function(){
    hello();
    function hello() { alert("Hello world"); }
  }())
} catch (err) {
  alert(err);
}

Natürlich sind Funktionen und Variablen, die innerhalb der try-Funktion definiert sind, im catch-Block nicht mehr sichtbar, wie sie es ohne die unmittelbare Funktionsumhüllung wären. Dies ist jedoch eine mögliche Abhilfe für Try/Catch-Skriptumhüllungen.

1voto

sworoc Punkte 1441

Auf diese Weise können Sie immer das Beste aus beiden Welten herausholen:

function hello() {
  alert("Hello world");
}

try {
  hello();
}
catch (err) {
  alert(err);
}

Sie erhalten immer noch Ihre Ausnahmen im Catch-Block, aber die Funktion ist verfügbar. Es sollte auch einfacher zu pflegen sein, und es gibt sowieso keinen funktionalen Vorteil, Funktionen zu hissen.

Editar:

Um zu zeigen, dass dies genauso haltbar ist wie das Einschließen des gesamten Codes in ein Try-Catch, gebe ich ein ausführlicheres Beispiel.

function hello(str) {
  alert("Hello, " + str);
}

function greet() {
  asdf
}

try {
  var user = "Bob";
  hello(user);
  greet();
  asdf
}
catch (e) {
  alert(e);
}

Dies funktioniert wie erwartet, ohne Probleme beim Parsen. Die einzigen Stellen, an denen es beim Laden scheitern könnte, sind außerhalb der Funktionsdefs und der try catch. Sie erhalten auch Ausnahmen auf jeden Müll innerhalb der Funktion defs.

Ich vermute, es ist eine stilistische Vorliebe, aber es scheint mir besser lesbar und wartbar zu sein als andere Optionen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X