Wow, aren't you thoroughly confused. Alright, I'll try to explain closures as simply as possible.
First, we'll start with scopes. There are two types of scopes:
- Block scopes
- Function scopes
A block scope begins immediately when it occurs in the program. A function scope on the other hand does not begin until the function is called. Hence multiple calls to the same function result in multiple scopes being created.
JavaScript does not have block scopes. It only has function scopes. Hence to emulate a block scope we need to create a function expression and immediately execute it. This patttern is called an immediately invoked function expression (IIFE) and it looks like this:
(function () {
// this is the JS equivalent of a block scope
}());
Beside block scopes and function scopes there's another way to classify scopes. Hence we also have:
- Lexical scopes
- Dynamic scopes
This distinction only applies to function scopes because block scopes are always lexically scoped. JavaScript only has lexical scopes.
To understand the difference between lexical scopes and dynamic scopes we need to understand the difference between free and bound variables.
- A free variable is a variable which is used within a function but which is not declared within that function.
- A variable which is declared within a function is said to be bound to that function.
Consider the following program:
function add(x, y) {
return x + y; // x and y are bound to add
}
In the above program the variables x
and y
are bound to the function add because they are declared within add
.
On the other hand the variables x
and y
in the following program are free within the function add
because they are not declared within add
but they are used within add
:
function add() {
return x + y; // x and y are free within add
}
Now free variables are a problem. They need to be mapped to some value, but which value? This is where lexical and dynamic scopes come into picture. I won't go into the major details, but you can read about it on Wikipedia.
Scopes are a lot like prototypal inheritance. When a new scope begins it inherits from a parent scope forming a chain of scopes much like prototype chains in JavaScript.
Lexical scopes and dynamic scopes differ with respect to which parent scope a new scope inherits form.
- In lexical scoping a new function scope inherits from the scope in which that function was defined (i.e. its lexical environment).
- In dynamic scoping a new function scope inherits from the scope in which that function was called (i.e. the calling scope).
Since JavaScript only has lexical scoping we won't bother with dynamic scoping. Consider the following program:
var count = 0;
function incrementCount() {
return ++count;
}
(function () {
var count = 100;
alert(incrementCount()); // 1
}());
Here the function incrementCounter
has one free variable - count
. Since JavaScript has lexical scoping count
will be mapped to the global variable count
instead of the local count
declared within the IIFE. Hence incrementCount
returns 1
and not 101
.
Now closures only work in languages which have lexical scoping. Consider the following program:
function getCounter() {
var count = 0;
return function () {
return ++count;
};
}
var counter = getCounter();
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3
In the above program the function returned by getCounter
is a closure with respect to the variable count
because:
- The variable
count
is free within the returned function (i.e. counter
).
- The function is moved outside of the scope within which
count
is declared.
Both these conditions are necessary for a function to be called a closure. For more information read the following answer: https://stackoverflow.com/a/12931785/783743
Now the important thing to understand here is that the function counter
will still be called a closure even though it may never be invoked. A closure is simply a function which closes over a variable (which is called the upvalue of the closure).
When we invoke getCounter
we create a new scope (let's call this scope A
), and each time we invoke the function returned by getCounter
(i.e. counter
) we create a new scope which inherits from scope A
. That's all. No new closure is created.