Closures
the lifetime of a variable
the new k-drama coming next fall
// global variables are "alive" and accessible during the life of the application
var bee_gees = 'stayin alive';
// create a new function scope
function childScope(){
// variables declared in here only live as long as this function block statement is executing
// or, as long as this function is on the stack
var fruitFly = 1;
// returns the value of fruitFly, not a reference to the local variable
return fruitFly;
}
// childScope is has not yet run, it is not yet on the stack
// what variables are currently "alive"?
// now invoke childScope
childScope(); // is now on the stack until it returns
Closures
are created when variables are accessed
outside of the immediate scope
Consider the following
var money = 55.50;
var cupsDrunk = 0;
var coffeeCost = 8.50;
function drinkCoffee(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
}
drinkCoffee();
drinkCoffee();
drinkCoffee();
console.log( cupsDrunk );
The original author's intention is to
increment cupsDrunk by calling
the drinkCoffee() function, which also depletes money
var money = 55.50;
var cupsDrunk = 0;
var coffeeCost = 8.50;
function drinkCoffee(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
}
drinkCoffee();
drinkCoffee();
drinkCoffee();
console.log( cupsDrunk ); // 3
console.log( money ); // 30
The variables are declared in the global scope
what if helpful Jason accesses cupsDrunk directly?
var money = 55.50;
var cupsDrunk = 0;
var coffeeCost = 8.50;
function drinkCoffee(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
}
cupsDrunk++;
cupsDrunk++;
cupsDrunk++;
// still 3, looks right
console.log( cupsDrunk );
Helpful Jason inadvertently broke the build!
var money = 55.50;
var cupsDrunk = 0;
var coffeeCost = 8.95;
function drinkCoffee(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
}
cupsDrunk++;
cupsDrunk++;
cupsDrunk++;
console.log( money ); // 55.50 !
Closures can be used to prevent that mistake
first, move cupsDrunk into the drinkCoffee() function
so that it's not globally accessible
var money = 55.50;
var coffeeCost = 8.50;
function drinkCoffee(){
// move the variable into the inner scope
var cupsDrunk = 0;
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
}
Create a Closure
declare a new function inside the inner scope drinkCoffee()
that has access to all variables in that scope
var money = 55.50;
var coffeeCost = 8.50;
// function expression assigned to drinkCoffee
var drinkCoffee = (function(){
var cupsDrunk = 0;
// closure is created when function accesses cupsDrunk
var checkFundsAndDrink = function(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++; // declared in immediate outer scope
}
}
return checkFundsAndDrink;
})(); // invoke function, returns checkFundsAndDrink
drinkCoffee();
drinkCoffee();
drinkCoffee();
console.log( cupsDrunk ); // error! undefined
Remove temporary variable
the checkFundsAndDrink variable is not really needed
var money = 55.50;
var coffeeCost = 8.50;
var drinkCoffee = (function(){
var cupsDrunk = 0;
return function(){ // removed var checkFundsAndDrink
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
};
})();
drinkCoffee();
drinkCoffee();
drinkCoffee();
console.log( cupsDrunk ); // error! undefined
How do we access cupsDrunk?
access the variables in the closure by returning the value
var money = 55.50;
var coffeeCost = 8.50;
var drinkCoffee = (function(){
var cupsDrunk = 0;
return function(){
if( money >= coffeeCost ){
money -= coffeeCost;
cupsDrunk++;
}
return cupsDrunk; // return the value
};
})();
var count;
count = drinkCoffee(); // 1
count = drinkCoffee(); // 2
count = drinkCoffee(); // 3
console.log( count ); // 3
console.log( money ); // 30
Closures
By Jon Borgonia
Closures
- 2,124