Es ist eine Frage von Scope. Code hat Zugriff auf die Variablen, die in der Funktion deklariert sind, auf ihre enthaltene Funktion (falls vorhanden), auf ihre enthaltene Funktion (falls vorhanden) usw. und dann auf globale Variablen.
In Ihrem ersten Beispiel ist readFileCallback
außerhalb des Rückrufs form.on
deklariert, und so hat es keinen Zugriff auf die Dinge in der form.on
Rückruf.
In Ihrem zweiten Beispiel ist die Funktion innerhalb der form.on
Rückruf, und so hat es Zugriff auf die Dinge darin.
Beachten Sie, dass im zweiten Beispiel in der Theorie eine neue Funktion jedes Mal erstellt wird, wenn der Rückruf aufgerufen wird. Das ist in Ordnung, JavaScript-Engines sind wirklich schnell beim Erstellen von Funktionen (und gute werden den Code wiederverwenden, obwohl ein separates Funktionsobjekt erstellt wird).
Normalerweise möchten Sie die Funktion an der äußersten Stelle erstellen, wo sie Zugriff auf alles hat, was sie benötigt. Also in Ihrem Fall wäre das innerhalbform.on
, aber außerhalb der readFile
Rückruf. Welches ist genau, wo dein zweites Beispiel es hat. Aber Sie können eine benannte Funktion wie Ihr erstes Beispiel, wenn Sie möchten, setzen Sie es nur inform.on
‚s Rückruf:
form.on('file', function(name, file){
fs.readFile(file.path, readFileCallback);
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
});
Nehmen wir ein Beispiel nehmen, wo alles einen einfachen Namen hatte, und folgen Sie durch zwei Anrufe:
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
inner(middleArg.toLowerCase());
}
middle(outerArg.toUpperCase());
}
outer
enthält middle
die inner
und outer
middle
Anrufe (Anrufe und middle
inner
) enthält.Ein Aufruf:
outer("Test1");
outer
bekommt das ARG "Test1"
- Es ruft
middle
mit "TEST1"
- Es ruft
inner
mit "test1"
inner
Ausgänge:
innerArg = test1
middleArg = TEST1
outerArg = Test1
So weit, so einfach, aber es ist spannender als das: Was passiert, wenn middle
eine Funktion zurückgibt, die inner
aufruft, anstatt sie sofort zu rufen, und outer
kehrt zurück middle
‚Rückgabewert s?
function outer(outerArg) {
function middle(middleArg) {
function inner(innerArg) {
console.log("innerArg = " + innerArg);
console.log("middleArg = " + middleArg);
console.log("outerArg = " + outerArg);
}
function caller() { // ***
inner(middleArg.toLowerCase()); // ***
} // ***
return caller; // ***
}
return middle(outerArg.toUpperCase()); // ***
}
Nun ruft outer
keine Ausgabe überhaupt haben:
var f = outer("Test2");
Aber dann Aufruf der Funktion middle
zurückgegeben (caller
) tut:
f();
Ausgang:
innerArg = test2
middleArg = TEST2
outerArg = Test2
Die Argumente existieren noch nach outer
und middle
zurück! Aber es ist noch interessanter:
var f1 = outer("Test3");
var f2 = outer("Test4");
f2(); // Note -- calling the second one first
f1();
Ausgang:
innerArg = test4
middleArg = TEST4
outerArg = Test4
innerArg = test3
middleArg = TEST3
outerArg = Test3
Das heißt also,, zweiouterArg
s noch existierte, nachdem beide Anrufe zu outer
fertig war, zusammen mit zweimiddleArgs
. Wie?
Sie existieren auf Objekte auf die Funktionen angehängt:
outer
Aufruf erzeugt ein Ausführungskontext (ein Objekt), die unter anderem (und eine Menge Details Weglassen) die Argumente und lokale hält Variablen für diesen Aufruf an outer
. Nennen wir es den "äußeren Kontext". Es hat auch einen Verweis auf den Ausführungskontext, der es enthält (der globale Kontext in unserem Code). Normalerweise wird dieses Objekt aufgeräumt, wenn ein Functon zurückkehrt ...
- ... aber
outer
erstellt eine Funktion, middle
. Wenn Sie eine Funktion erstellen, wird der aktuelle Ausführungskontext an die Funktion angehängt. So hat es Zugriff auf die Variablen und so in diesem äußeren Kontext.
outer
ruft middle
, einen inneren Ausführungskontext zu schaffen und middle
erzeugt zwei andere Funktion (inner
und caller
), die jeweils erhalten, dass die innere Rahmen mit ihnen verbunden.middle
dann gibtcaller
zurück, so caller
existiert, nachdem der Anruf zu middle
abgeschlossen ist. Da caller
einen Verweis auf den inneren Ausführungskontext hat, besteht der Kontext weiterhin (genau wie jedes andere Objekt), obwohl middle
zurückgegeben wurde. Da dieser Zusammenhang eine Bezugnahme auf inner
, inner
hat, existiert auch weiter bestehen.
outer
gibt den Rückgabewert von middle
(die caller
ist), und so besteht das bedeutet caller
noch, wenn outer
zurückgibt, das heißt, den inneren Zusammenhang noch bezieht sich auf existiert, die inner
noch Mittel vorhanden ist, und der äußere Rahmen existiert immer noch, weil der innere Kontext einen Bezug darauf hat.
... das ist, wie f1
und f2
Zugriff auf diese Argumente haben nach outer
zurückkehrt: Wenn man sie laufen, sie sehen die Werte in den Kontexten oben mit ihnen verbunden.
Die erste wird innerhalb des Bereichs der übergeordneten Funktion definiert, sodass Zugriff auf die lokalen Variablen der umschließenden Funktion besteht. Der zweite ist außerhalb definiert und nicht eingeschlossen. – gurvinder372
Eng verwandt: [* Wie funktionieren JavaScript-Verschlüsse? *] (Http://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1) –