Yup. Functions are first class objects. They can be stored in variables, passed around, and even given custom properties just like any other object. In fact, they’re like other objects in just about every other way except you also get a special behavior if you put () after their identifiers which invokes the code stored in the function’s body.
var obj = {};
function fun () {}
var temp;
temp = obj;
temp = fun; // OK
console.log(obj);
console.log(fun); // OK
obj.myValue = 1;
fun.myValue = 1; // OK
fun();
obj(); // NOT OK
What makes a function a closure is when it uses 1 or more [non-global] variables within its function body that aren’t a part of that function’s parameters or otherwise declared within the function itself. The getDelay function in your example does this with the startTime variable. startTime is declared in stopWatch, outside of getDelay, yet getDelay’s function body reaches out and accesses it to use for itself. When it does this, it creates a reference to that variable and can access it whenever its called.
Closures then become similar to objects with special “properties” that exist as references to other variables. stopWatch creates a getDelay function that has a kind of startTime property associated with it, though its hidden from you the user because its not actually a property… though it could have been. Consider stopWatch written another way, since, after all, we just saw how functions can be given properties like objects:
function stopWatch () {
function getDelay() {
var elapsedTime = Date.now() - getDelay.startTime;
alert(elapsedTime);
}
getDelay.startTime = Date.now();
return getDelay;
}
This works the same way, only the variable we’re using to capture the startTime is assigned directly to the getDelay function. This also means its accessible in timer, the variable getDelay is assigned to when stopWatch() is called.
var timer = stopWatch();
alert(timer.startTime); // alerts startTime value set in stopWatch
The closure version doesn’t expose startTime as a property, though. Its simply an internal reference to the original variable from whatever scope it was originally defined. In stopWatch, its the local scope of the stopWatch() call. Normally local variables in a function call are destroyed when the function completes and returns, but since getDelay hangs on to startTime as a closure variable, it gets to live as long as getDelay (assigned to timer) does.
Ultimately, this becomes the purpose of the stopWatch function. Its a factory creating startTime variables and getDelay functions that access them. Each time its called, new versions of that variable and function are created, and though only the function is returned, the variable is still being used because of the closure reference that the function keeps to it.
Closures can get tricky, and it may take a while to get your head around them. The important bit is that closure variables are references not copies. Often people assume the value of a closure variable gets baked into a function, but thats not true. The value of the variable is accessed when the function is run, not created. This will often confuse people when creating functions in loops.
var funcs = [];
for (var i = 0; i < 3; i++) {
function alertLoopValue () {
alert(i);
}
funcs.push(alertLoopValue);
}
var lastFunc = funcs[2];
lastFunc(); // what's alerted?
At first glance, it looks like the obvious behavior here is that funcs[0] would alert 0, funcs[1] would alert 1, and funcs[2] would alert 2. But truth is, lastFunc, as well as all of the other functions in the funs array would alert 3. This is because, when you call them, them loop has already run through and incremented the i variable to 3, the first value that fails the loop condition of i < 3. And since closure variables are references, not copies, the value of i when the function is called gets used, not when it was created in the loop. There’s only one i variable, and every func function references that same variable and at this point, after the loop, that variable’s value is 3.
…It takes time. 