It's a matter of scope. Code has access to the variables declared within the function, its containing function (if any), its containing function (if any), and so on, and then globals.
In your first example, readFileCallback is declared outside the form.on callback, and so it doesn't have access to things inside the form.on callback.
In your second example, the function is inside the form.on callback, and so it does have access to the things inside it.
Note that in the second example, in theory a new function is created each time the callback is called. That's fine, JavaScript engines are really fast at creating functions (and good ones will reuse the code even though a separate function object is created).
Normally you want to create the function at the outermost location where it has access to everything it needs. So in your case, that would be inside form.on, but outside the readFile callback. Which is exactly where your second example has it. But you can use a named function like your first example if you like, just put it in form.on's callback:
form.on('file', function(name, file){
fs.readFile(file.path, readFileCallback);
function readFileCallback(err, contents){
console.log(file);
if (err) throw err;
....
}
});
Let's take an example where everything had a simple name, and follow through two calls:
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 contains middle which contains inner, and outer calls middle (and middle calls inner). A call:
outer("Test1");
outer gets the arg "Test1"
- It calls
middle with "TEST1"
- It calls
inner with "test1"
inner outputs:
innerArg = test1
middleArg = TEST1
outerArg = Test1
So far, so simple, but it's more exciting than that: What if middle returns a function that calls inner, instead of calling it immediately, and outer returns returns middle's return value?
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()); // ***
}
Now, calling outer doesn't have any output at all:
var f = outer("Test2");
But then calling the function middle returned (caller) does:
f();
Output:
innerArg = test2
middleArg = TEST2
outerArg = Test2
The arguments still exist after outer and middle return! But it's even more interesting:
var f1 = outer("Test3");
var f2 = outer("Test4");
f2(); // Note -- calling the second one first
f1();
Output:
innerArg = test4
middleArg = TEST4
outerArg = Test4
innerArg = test3
middleArg = TEST3
outerArg = Test3
So that means, two outerArgs still existed after both calls to outer had finished, along with two middleArgs. How?
They exist on objects attached to the functions:
- Calling
outer creates an execution context (an object), which amongst other things (and leaving out a lot of details) holds the arguments and local variables for that call to outer. Let's call it the "outer context." It also has a reference to the execution context containing it (the global context, in our code). Normally that object gets cleaned up when a functon returns...
- ...but
outer creates a function, middle. When you create a function, the current execution context is attached to the function. That's how it has access to the variables and such in that outer context.
outer calls middle, creating an inner execution context, and middle creates two other function (inner and caller), which each get that inner context attached to them. middle then returns caller, so caller exists after the call to middle completes. Since caller has a reference to the inner execution context, the context continues to exist (just like any other object), even though middle has returned. Since that context has a reference to inner, inner also continues to exist.
outer returns the return value of middle (which is caller), and so that means caller still exists when outer returns, which means the inner context it refers to still exists, which means inner still exists, and the outer context still exists because the inner context has a reference to it.
...which is how f1 and f2 have access to those arguments after outer returns: When you run them, they look up the values in the contexts attached to them.