In JavaScript, when using a function expression (e.g. var myFunc = function() {...}
), like any other variable declaration, you have to define the variable before using it. For example, the following example will not work (will result in Uncaught TypeError: myFunc is not a function
):
var myVar = myFunc();
var myFunc = function() {
// code here...
}
However, in my routes/index.js file of a node js project, I have the following code (abbreviated obviously):
var router = express.Router();
.
.
.
router.post('/', function(req, res) {
...
...
var myVar = myFunc(); // WORKS!
...
...
}
var myFunc = function() {
...
}
The myFunc
variable is declared after it is used, so shouldn't this throw an error?
There are two aspects to this:
Why can the callback passed to router.post
access the myFunc
variable, when the variable declaration is below it in the code?
Why can the callback passed to router.post
access the function assigned to the myFunc
variable, when it's not assigned to the variable until below it in the code?
First we'll deal with the variable, then we'll deal with its value (the function we assign to it):
The myFunc variable is declared after it is used, so shouldn't this throw an error?
It would if var
weren't hoisted. But var
is hoisted. So when your module is loaded, first the JavaScript engine looks through it to find all variable declarations and function declarations, processes those, and then does the step-by-step code in your module.
E.g., to the JavaScript engine, your module actually looks like this:
var router = undefined;
var myFunc = undefined;
router = express.Router();
.
.
.
router.post('/', function(req, res) {
var myVar = undefined;
...
...
myVar = myFunc(); // WORKS!
...
...
}
myFunc = function() {
...
}
More on this on my anemic little blog: Poor misunderstood var
Why doesn't the location of a function expression matter in node js?
It does. The only reason you're not running into trouble is that myFunc
isn't used until the callback you're passing into router.post
is called, which is after the top-level scope code of your module script has been run (including the expression creating myFunc
).
E.g., what happens is:
The prep stuff (creating the vars router
and myFunc
and setting them to undefined
)
The express.Router
call, which assigns a new value to router
The call to router.post
, passing in but not calling a callback function
Creation of the function, which assigns a new value to myFunc
Later, when a request comes in, the callback is called, by which time myFunc
has been created (and is accessible because the callback is a closure over the context where myFunc
is declared)
This is analogous to this:
setTimeout(function() {
var myVar = myFunc();
}, 0);
var myFunc = function() {
// code here...
}
First setTimeout
is called, then the function is created and assigned to myFunc
, then later the callback function is called and calls the function via myFunc
.