2008-11-04 3 views
135

Dieser Code funktioniert immer, auch in verschiedenen Browsern: obwohlWarum kann ich eine Funktion verwenden, bevor sie in JavaScript definiert ist?

function fooCheck() { 
    alert(internalFoo()); // We are using internalFoo() here... 

    return internalFoo(); // And here, even though it has not been defined... 

    function internalFoo() { return true; } //...until here! 
} 

fooCheck(); 

ich nicht einen einzigen Hinweis auf, warum es sollte funktionieren finden konnte. Ich sah das zuerst in John Resigs Vortragsnotiz, aber es wurde nur erwähnt. Es gibt keine Erklärung dafür oder sonst wo.

Könnte jemand bitte mich aufklären?

+2

In neueren Versionen von Firefox, das funktioniert nicht, wenn der Code in einem Try/Catch ist. Siehe diese Geige: http://jsfiddle.net/qzzc1evt/ –

Antwort

182

Die Deklaration function ist magisch und bewirkt, dass ihr Bezeichner gebunden wird, bevor irgendetwas in ihrem Codeblock * ausgeführt wird.

Dies unterscheidet sich von einer Zuweisung mit einem function Ausdruck, der in normaler Top-Down-Reihenfolge ausgewertet wird.

Wenn Sie das Beispiel geändert zu sagen:

var internalFoo = function() { return true; }; 

würde es aufhören zu arbeiten.

Die Funktionsdeklaration ist syntaktisch ziemlich vom Funktionsausdruck getrennt, obwohl sie fast identisch aussieht und in einigen Fällen mehrdeutig sein kann.

Dies ist in der ECMAScript standard, Abschnitt 10.1.3 dokumentiert. Leider ist ECMA-262 selbst nach Standards kein sehr lesenswertes Dokument!

*: die enthaltene Funktion, Block, Modul oder Skript.

+0

Ich denke, es ist wirklich nicht lesbar. Ich habe gerade den Abschnitt gelesen, auf den Sie hingewiesen haben 10.1.3 und nicht verstanden, warum die Bestimmungen dort dieses Verhalten verursachen würden. Danke für die Information. –

+24

Das nennt man "hissen", oder? –

+0

@Mathias: richtig. – bobince

2

Einige Sprachen haben die Anforderung, dass Kennungen haben vor der Verwendung definiert werden. Ein Grund dafür ist, dass der Compiler einen einzigen Durchlauf des Quellcodes verwendet.

Aber wenn es mehrere Durchgänge gibt (oder einige Schecks verschoben werden), können Sie ohne diese Anforderung perfekt leben. In diesem Fall wird der Code wahrscheinlich zuerst gelesen (und interpretiert) und dann werden die Links gesetzt.

0

Der Body der Funktion "internalFoo" muss irgendwo zur Parsing-Zeit gehen, also wenn der Code vom JS-Interpreter gelesen wird (a.k.a parsing), wird die Datenstruktur für die Funktion erstellt und der Name zugewiesen.

Erst später, dann der Code ausgeführt wird, JavaScript tatsächlich versucht, um herauszufinden, ob „internalFoo“ existiert und was es ist und ob sie aufgerufen werden kann, usw.

13

Der Browser Ihr HTML vom Anfang bis zum Ende liest und kann es so ausführen, wie es gelesen wird und in ausführbare Stücke zerlegt wird (Variablendeklarationen, Funktionsdefinitionen, etc.) Aber an irgendeinem Punkt kann nur verwenden, was in dem HTML vor diesem Punkt definiert worden ist.

Dies unterscheidet sich von anderen Programmierkontexten, die Ihren gesamten Quellcode verarbeiten (kompilieren), ihn mit allen benötigten Bibliotheken verknüpfen und ein ausführbares Modul erstellen, an dem die Ausführung beginnt.

Sie können Funktionen definieren, die sich auf Elemente (Variablen, andere Funktionen usw.) beziehen, die weiter definiert werden. Sie können diese Funktionen jedoch erst ausführen, wenn alle Teile verfügbar sind.

Sobald Sie sich mit JavaScript vertraut gemacht haben, werden Sie sich der Notwendigkeit bewusst, Dinge in der richtigen Reihenfolge zu schreiben.

Revision: Um die akzeptierte Antwort (oben) zu bestätigen, verwenden Sie Firebug, um durch den Skriptabschnitt einer Webseite zu gehen. Sie werden sehen, dass es von Funktion zu Funktion überspringt und nur die erste Zeile aufruft, bevor tatsächlich Code ausgeführt wird.

+4

+1 für die Revision am Ende Ihrer Antwort, die der wesentliche Teil ist. – hippietrail

-4

Aus dem gleichen Grunde wird folgende immer foo im globalen Namespace setzen:

if (test condition) { 
    var foo; 
} 
+8

Eigentlich ist es aus sehr unterschiedlichen Gründen. Der 'if'-Block erstellt keinen Bereich, während ein' function() '-Block immer einen erstellt. Der wahre Grund war, dass die Definition von globalen Javascript-Namen in der Kompilierungsphase erfolgt, so dass der Name selbst dann definiert ist, wenn der Code nicht ausgeführt wird. (Entschuldigung, es dauerte so lange, einen Kommentar abzugeben) –

4

Es wird HEBE genannt - Invoke (genannt) eine Funktion vor, wo es definiert wurde.

Zwei verschiedene Arten von Funktionen, die ich schreiben möchte, sind:

Ausdrücke Funktionen & Verzögerungsfunktionen

  1. Ausdrücke Funktionen:

    Eine Funktion Ausdruck in einer Variablen gespeichert werden kann, so Sie benötigen keine Funktionsnamen. Sie werden auch als anonyme Funktion (eine Funktion ohne Namen) benannt.

    aufzurufen (genannt) sind sie immer einen Variablennamen verwenden müssen. Diese Art von Funktionen funktioniert nicht, wenn zuvor Anrufe getätigt wurden, was bedeutet, dass das Hochziehen hier nicht stattfindet. Wir müssen immer zuerst die Ausdrucksfunktion definieren und dann aufrufen.

    let lastName = function (family) { 
    console.log("My last name is " + family); 
    }; 
    let x = lastName("Lopez"); 
    

    Dies ist, wie Sie in ECMAScript   6 schreiben:

    lastName = (family) => console.log("My last name is " + family); 
    
    x = lastName("Lopez"); 
    
  2. Verzögerungs Funktionen:

    Funktionen werden erklärt mit folgenden Syntax sofort werden nicht ausgeführt. Sie werden "für die spätere Verwendung gespeichert" und werden später ausgeführt, wenn sie aufgerufen (aufgerufen) werden. Diese Art von Funktionen funktionieren, wenn Sie sie vor oder nach dem Zeitpunkt aufrufen, an dem sie definiert wurden. Wenn Sie eine Verzögerungsfunktion aufrufen, bevor sie definiert wurde - Hochziehen - funktioniert ordnungsgemäß.

    function Name(name) { 
        console.log("My cat's name is " + name); 
    } 
    Name("Chloe"); 
    

    Hoisting Beispiel:

    Name("Chloe"); 
    function Name(name) { 
        console.log("My cat's name is " + name); 
    } 
    
Verwandte Themen