It gives a good review of javascript syntax, goes over the intricacies of the loose typing system and variable scope, covers some detail on avoiding memory leaks and some browser specifics (which I think are probably out of date; I didn't review it thoroughly I was playing Minecraft at the time) and gets up to anonymous functions and closures.
Aside: Incidentally if someone would like to explain closures to me I'd appreciate it - I don't really understand them.
Code Academy's [2] javascript looks very basic but Code School [3] seems to have better beginner stuff - I've done their git/jQuery courses before and they were quite well done.
HTH.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re...
[2] Avoid for javascript, very basic: http://www.codecademy.com/courses/getting-started-v2/0/1?cur...
[3] https://www.codeschool.com/courses/javascript-best-practices
If you truly want to understand how it works then you'd probably want to write a compiler that supports closures; you'd then need to cover issues like how to allocate functions on the heap, the difference between locally allocated (typically on the stack) data bound to functions and globally allocated (typically on the heap) data bound to functions.
The second part to closures is understanding the theory, or the why and the high level functionality that it enables, such as callbacks with state or interactions with the likes of recursive (y-combinator like) functions.
EDIT: minor grammar fix
http://c2.com/cgi/wiki?ClosuresAndObjectsAreEquivalent
A singular closure is 1+ data bound to an entity (function). A singular object is multiple data/functions bound to one entity (object).
In the link above there are examples of either generating multiple closures tied to the same set of data (like tel's example), and also examples of having a singular closure that takes as a first parameter a "method" name and branching based on that. Using either solution you have an OO system using closures as your basis.
These variables also won't get garbage collected because of that.
This feature is most useful when you create anonymous functions that you pass around.
Example:
function foo() {
var localVariable = 3;
return (function () { // this anonymous function can reference localVariable because it is a closure and remembers outside scope
localVariable++;
alert(localVariable);
})
}
var increase = foo(); //foo returns freshly created anonymous function that we assign to local variable "increase".
//foo also created local variable "localVariable"
//and it went out of scope when foo returned,
//but that variable won't be GC-ed as long we keep reference to "increase",
//because increase has that "localVariable" in scope
increase() // we call that variable - it executes that functions and writes 4
function bar() {
var localVariable = 100; //this is different variable with the same name
increase(); //bar can reference increase because bar is a closure, so it remembers outside scope
}
bar(); // writes 5
increase(); //writes 6
var increase2 = foo(); // this creates another function and another localVariable
increase2(); //writes 4
increase(); //writes 7
It's useful for similar things as objects in OO programming (grouping data with code), but encourages different approach to this.Closures also make functional code with passing functions bearable - without it you would have to explicitly pass variables from scope to each function, or to depend on dynamic scope, so your functions would use different variables depending where they are called.
I should probably be more precise - only the variables from outside scope that the closure actually uses won't get GCed as long as that closure is referenced. Other variables will.
You're used to thinking of functions which act on things passed into them via their parameters. For instance:
function apply(f, x) { return f(x); }
My example, apply, is a bit unique in that it only uses things passed in through the parameters. More normally, you might also use names of things available in the scope when you define the function, for instance: function log(x) { console.log(x); }
In this example, the behavior of add depends not only on the parameter x but also the fact that console.log is defined ambiently.What a closure refers to is the fact that functions can capture names which are only ever available locally thus hiding a reference inside of them. A simple example might be:
function makeExample() {
var exampleText = "Hello world";
return function printer() {
console.log(exampleText);
}
}
var myPrinter = makeExample();
printer();
// Hello world
In this case, the variable `exampleText` is clearly being captured in the definition of `printer`, but since `exampleText` is only defined in the scope of `makeExample`, we have no way of accessing it. The function stored at `myPrinter` has closed over its own copy of `exampleText` can uses it internally in a way we cannot access.So finally we can turn to the more interesting examples where we combine this closure/capture property with mutability. The canonical example is the counter:
function makeCounter() {
var count = 0;
return {
get: function get() { return count; },
inc: function inc() { count += 1; },
dec: function dec() { count -= 1; }
}
}
var myCounter = makeCounter();
var get = myCounter.get;
var inc = myCounter.inc;
var dec = myCounter.dec;
assert(get() === 0);
inc();
assert(get() === 1);
dec();
assert(get() === 0);
Here, `makeCounter` returns a struct of functions which have all independently captured a reference to the same hidden variable `count`. While I return them all together in an object, I also destructure that object to stress that there's nothing funny going on—the three functions have to be created together to capture the same `count` variable, but afterward they can be separated far and wide.Since all three functions reference the same hidden variable state they can manipulate it together. This is the magic of variable capture under mutable state: closures.
---
So what's the point?
Well, we've essentially created a private mutable variable on a home-grown object system. There is no way for someone to access the secret `count` reference except via the get/inc/dec functions which have closed over it. This can be very valuable for data encapsulation.
To skip to the punch, Javascript only has a reasonable module system because of closures. If you're familiar with the IIFE-based modules of Javascript they go a little like this
exports = {};
(function(exports) {
var count = 0;
function inc() { count += 1 };
function dec() { count -= 1 };
// With only this function and not `get` exported we can never
// actually view the value of count. This can be very useful
// for implementation hiding and building a minimal API.
function isEven() { return count % 2 == 0 };
exports = { inc: inc, dec: dec, isEven: isEven };
})(exports)
Here we see that the IIFE creates a private, local scope where names like `count` can be created and closed over by exported functions like `inc`, `dec`, and `isEven`. This public/private API building is the core of module creation and, ultimately, it rests upon the creation of closures.