Closure
Core Concepts
First-Class Function
First-class functions can be constructed at runtime and assigned to variables. They can also be passed to, and returned by other functions. In addition to meeting the previously mentioned criteria, JavaScript functions also have their own properties and methods.
Inner Function
Functions that are defined inside of another function. Each time the outer function is called, an instance of the inner function is created. One important characteristic of inner functions is that they have implicit access to the outer function's scope. This means that the inner function can use the variables, arguments, etc of the outer function.
Lexical environment
Internal implementation of the JavaScript scoping methanism, and people often colloquially refer to them as scope
Forward reference
Hoisting
Variable and function declarations are hoisted, or lifted, to the top of a function or global scope.
What is Closure
A closure is the process of preventing the garbage collector from removing a variable from memory by keeping access to the variable outside the execution context in which it created.
A closure allows a function to access and manipulate variables that are external to that function. Closures allow a function to access all the variables, as well as other functions, that are in scope when the function itself is defined.
global scope is a closure too
When a function (inner) is declared inside a function (outer), not only is the function declaration defined, but a closure is created that encompasses the function defintion as well as all variables in scope at the point of function definition.
When inner function is executes, even if it is executed after the scope in which it was declared goes away, it has access to the original scope in which it was declared through its closure.That’s what closures are all about. They create a “safety bubble” of the function and the variables in scope at the point of the function’s definition, so that the function has all it needs to execute. This bubble, containing the function and its variables, stays around as long as the function does.
From MDN:
A closure is a special kind of object that combines two things:
A function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.
How closure works
A unique execution context object is created every thime a function is called. After the function completes, the execution object is immediately discarded unles the caller retains a reference to it. If a function return a number, you can't typicaly retain a reference to a function's execution context object. On the other hand, if a function returns a more complex structure like, a function, an object, or an array, creating a reference to the execution context is often accomplished (by storing the return value to a variable)
In JavaScript, if you use the function keyword inside another function, you are creating a closure. If you declare a function within another function, then the local variables can remain accessible after returning from the funciton calls.
Every time we invoke a constructor function, we create a new lexical environment, which keeps track of variables local to the constructor. In this example, a new Ninja environment that keeps track of the feints variable is created. In addition, whenever a function is created, it keeps a reference to the lexical environment in which it was created (through an internal [[Environment]] property). In this case, within the Ninja constructor function, we create two new functions: getFeints and feint, which get a reference to the Ninja environment, because this is the environment in which they were created.
The getFeints and feint functions are assigned as methods of the newly created ninja object (which, if you remember from the previous chapter, is accessible through the this keyword). Therefore, getFeints and feint will be accessible from outside the Ninja constructor function, which in turn leads to the fact that you’ve effectively created a closure around the feints variable.
The method keep alive the environments in which they were created, thus keeping alive the "private" variable of each instance [LW] becasue the method keep the reference of the function (Ninja), so it keep the referece of the variable.
Every object created with the Ninja constructor gets its own methods (the ninja1.getFeints method is different from the ninja2.getFeints method) that close around the variables defined when the constructor was invoked. These “private” variables are accessible only through object methods created within the constructor, and not directly!
Because every function call causes the creation of a new execution context
As you might have figured out by now, these “private” variables aren’t private properties of the object, but are variables kept alive by the object methods created in the constructor.
How to create closure
A closure is created when an inner funciton is made accessible from outside of the function that created it. This typically occurs when an outer function returns an inner function. When this happens, the inner function maintains a reference to the environment in which it was created. This means that it remembers all fo the variables (and their values) that were in scope at the time.
When a function has nested function inside of it, the nested function has access to the vars and parameters of the outer function and a "closure" is created behind the scense.
A closure is an inner function that has access to the outer (enclosing) funciton's variables - scope chain
A closure is created that encompasses a function declaration, but also ALL varialbes that are currently in same scope (including before and after) at the point of declaration. It creates a safety bubble.
Putting Closure to Work
- Mimicking private variables.
function Ninja() {
var feints = 0;
this.getFeints = function() {
return feints;
};
// create a closure
this.feint = function(){
feints++;
};
}
var ninja = new Ninja();
ninja.feint();
assert(ninja.feints === undefined, "And the private data is inaccessible to us." );
assert(ninja.getFeints() == 1,"We're able to access the internal feint count." );
There’s another important concept that this example makes clear. Not only can we see the values that these variables had at the time the closure was created, but we can update them within the closure while the function within the closure executes. The closure isn’t just a snapshot of the state of the scope at the time of creation, but an active encapsulation of that state that we can modify as long as the closure exists.
Taking advantage of functions as first-class objects. Whenever a function is created, a reference to the lexical environment in which the function was created is stored in an internal (meaning that you can’t access or manipulate it directly) property named [[Environment]]
; double brackets is the notation that we’ll use to mark these internal properties.
That execution of JavaScript code occurs in two phases.
The first phase
is activated whenever a new lexical environment is created. In this phase, the code isn’t executed, but the JavaScript engine visits and registers all declared variables and functions within the current lexical environment.
The second phase
, JavaScript execution, starts after this has been accomplished; the exact behavior depends on the type of variable (let, var, const, function declaration) and the type of environment (global, function, or block).
One of the features that makes JavaScript pleasant to use is that the order of function definitions doesn’t matter. (this holds for function declaration, function expression and arrow function aren't part of this process)
Using closure with callbacks
Situations where you might want to do this are particularly common on the web.Much of the code we write in web JavaScript is event-based — we define some behavior, then attach it to an event that is triggered by the user (such as a click or a keypress).Our code is generally attached as a callback: a single function which is executed in response to the event.
Revealing Module Pattern
var prison = (function () {
var prisoner_name = 'Mike';
var jail_term = '20 years term';
// instead of adding the variabless to the global scope
// only the varialbe prison is added.
// it reduces in global variables
return {
prisoner : prisoner_name + ' - ' + jail_term,
sentence: jail_term
};
})();
// output : undefined
// cannot access private variable
console.log(prison.prisoner_name);
console.log(prison.prisoner);
console.log(prison.sentence);
// try to access the private property
// but just create new attribute,
prison.jail_term = 'free';
console.log(prison.jail_term);
console.log(prison.sentence);
// prisoner_name and jail_term aren't properties
// of the object saved to the variable prison,
// so they cannot be accessed this way.
// They are variables used to define the
// attributes prisoner and sentence on the object
// returned from anonymous function, and those attributes
// can be accessed on the prison variable.
// 1. jail_term isn't an attribute on the prison object or prtotype;
// it was a variable in the execution context that created the object
// and saved to the prison variable, and that execution context no longer exists
// because the function finished executing already.
// 2. these attributes are set one time when the anonymous function is executed
// and never updated. To make them update, we have to turn the attributes into methods that
// access the variable every time they're invoked.
var prison2 = (function () {
var prisoner_name = 'Mike';
var jail_term = '20 years term';
return {
prisoner : function () {
return prisoner_name + ' - ' + jail_term;
},
setJailTerm : function ( term ) {
jail_term = term;
}
};
})();
console.log(prison2.prisoner());
prison2.setJailTerm('Sentence commuted');
// jail term is updated.
console.log(prison2.prisoner());
- Saving variable in Ajax Call
var prison = {
names: 'Josh Powell and Mike Mikowski',
who: function () {
$.ajax({
success: function () {
console.log( this.names );
}
});
}
};
// outputs undefined, 'this' is the ajax object
prison.who();
// Closures to the rescue!
// Remember, a closure is created by taking a function that has access to a variable
// in the current execution context and saving it to a variable outside of the current execution context.
var prison = {
names: 'Mike Mikowski and Josh Powell',
who: function () {
var that = this;
$.ajax({
success: function () {
console.log( that.names );
}
});
}
};
// outputs 'Mike Mikowski and Josh Powell'
prison.who();
// How Closure is implemented
When Not to Use Closure
In Loop
Creating closure within loops can have misleading results.
Unnecessary Use in Constructors
Reference
- JavaScript Closures for Dummies
- Mozilla - Colsure
- Understand JavaScript Closures with Ease
- Why is colsure important for JavaScript
- What's so useful about closures in JS?
- What is practical use for closure in JavaScript?
- Why use "Closure"
- Getting Closure
- A Random Exploration of Closure use Case in JavaScript
- When and How to use JavaScript Closures
- Closure: Front to Back
- JavaScript Closure - examples
- Understanding JavaScript Closures