Closures - A protective bubble
Below, we define a function outer
and var globalValue
at Global level.
Inside the outer
function we define function inner
and outerValue
.
Inside the inner
function we define innerValue
. To cross verify that inner
function has access to all the variables we log globalValue, outerValue and innerValue
.
It logs all the three values i.e. globalValue
, outerValue
,innerValue
.
However, it will fail if we try to access innerValue
anywhere else than the lexical scope of that variable.
var globalValue = 'Global Val';
function outer(){
var outerValue = 'Outer Val';
function inner(){
var innerValue = 'Inner Val';
console.log(globalValue + '\n' + outerValue + '\n' + innerValue);
}
inner();
}
outer();
Now, we will see have a closer look to closures.
So, in the example above we have quite proved the sneakiness of the inner function.
Now, if we would invoke inner on global level, it would return an error.
The reason that it throws an error is because as execution reaches inner()
var globalValue = 'Global Val';
function outer(){
var outerValue = 'Outer Val';
function inner(){
var innerValue = 'Inner Val';
console.log(globalValue + '\n' + outerValue + '\n' + innerValue);
}
}
inner(); // error
outer();
The work around for that is to declare a global variable ref1
.
While, JS engine execution stage starts. It invokes outer()
, and it creates an execution context for the outer
function. It creates execution stack
for the outer
function.
And before the execution stack ends it assigns the value of inner
in global var ref
.
The outer execution stack
has ended right now.
Even though the global execution stack
is back in action. We have access to all the variables of the function outer
and inner
through the reference of inner
function stored in global variable ref
. There you go, that is a closure
.
var globalValue = 'Global Val';
var ref;
function outer(){
var outerValue = 'Outer Val';
function inner(){
var innerValue = 'Inner Val';
console.log(globalValue + '\n' + outerValue + '\n' + innerValue);
}
ref = inner;
}
outer();
ref();
Below we are adding one more level to it. Yes, although it is useless but it will get even clearer to understand how the levels of passing the value of function innermost
to reference variable ref2
creates a closure
again.
var globalValue = 'Global Val';
var ref1,ref2;
function outer(){
var outerValue = 'Outer Val';
function inner(){
var innerValue = 'Inner Val';
function innermost(){
var innermostVal = 'Inner most Val' ;
console.log(globalValue + '\n' + outerValue + '\n' + innerValue);
}
ref2 = innermost;
}
ref1 = inner;
}
outer();
ref1();
ref2();
Closures also work in case the parameter value is passed to the function.
var globalValue = 'Global Val';
var ref;
function outer(){
var outerValue = 'Outer Val';
function inner(parameter){
var innerValue = 'Inner Val';
console.log(globalValue + '\n' + outerValue + '\n' + innerValue + '\n' + parameter);
}
ref = inner;
}
outer();
ref();
Putting closures to work
Create private variables.
Below we have created a constructor function pubName
and passed a parameter pName
. It has a variable storing the name
value in it from the argument being passed.
A new instance of the pubName
function is created using var xMen = new pubName('wolverine');
.
When a new instance is created, the variable name
stays private to the newly created object xMen
. However, we have defined a method which helps us to access the private variable using the closure which is created.
When we invoke the method xMen.getName();
it returns the value wolverine
.
function pubName(pName){
var name = pName;
this.getName= function(){
return name;
}
}
var xMen = new pubName('wolverine');
Good.