preface
When was the closure created and when was it destroyed? What about the implementation?
At the beginning of learning closures, I swallowed the date π. I hope this time I can calm down and meditate, and have a deeper understanding of closures.
π€ To better understand closures, it is necessary to understand the scope and execution context:
JavaScript execution context – Execution stack
Javascript dynamic scope you don’t know about
Words don’t say much, come up is a thinking question π€
var name = "The Window";
var object = {
name: "My Object".getNameFunc: function () {
return function () {
return this.name; }; }}; alert(object.getNameFunc()());Copy the code
π of course, the JS foundation is solid, must understand the inside of the review, look at the content, for this problem will be able to solve the β
Click here to see
Obj.getnamefunc ()() actually calls an anonymous function in the global scope; this refers to the window. The function name is separated from the function (or function value). Do not assume that the this inside the function refers to where the function is. The execution environment of anonymous functions is global, so their this object usually points to window
What is a closure
To see how ruby said π
Closures are functions that have access to variables in the scope of another functionCopy the code
Let’s start with the MDN definition π
Function and references to its surrounding state (**lexical environment **) are bundled together to form the **closure** (**closure**). That is, closures allow you to access outer function scopes from inner functions. In JavaScript, whenever a function is created, a closure is generated when the function is generated.Copy the code
Closures are functions that can access free variables. Arguments free variables refer to variables that are used in a function, but are neither function arguments nor local variables to the function.
There are a variety of definitions for closures on the Internet. Everyone's understanding of closures is different, so I don't want to define closures, so I can decide πCopy the code
If you want to understand, there are two ways to understand:
1οΈ closure is a nested internal function (most people)
2οΈ one of the objects (few people) containing the variable (or function) being referenced
I think closures exist with nested internal functions π
For the second understanding, let’s write a demoπ
function count () {
var x = 0
return {
add() {
x++;
},
print() {
console.log(x)
}
}
}
let demo = count();
demo.add()
demo.print()
demo.add()
demo.print()
Copy the code
Well π can only be understood can not be explained, go down to see again!
The life cycle of closures
Closure causes
The first thing to understand is the concept of scope chains, which is actually quite simple. There are only two scopes in ES5
1οΈ global scope 2οΈ local scope
When accessing a variable, the interpreter first looks for an identifier in the current scope. If it doesn’t find one, the interpreter looks in the parent scope until the variable’s identifier is found or not in the parent scope. This is the scope chain. Note that each subfunction copies the parent scope, forming a chain of scopes. Such as:
var x = 1;
function demo() {
var x = 2
function demo2() {
var x = 3;
console.log(x);/ / 3}}Copy the code
In the above code, I personally understand that the scope of demo function refers to the global scope (window) and itself, while the scope of demo2 function refers to the global scope (window), demo and itself. If the global scope is not found, an error β will be reported
The nature of closure generation π― There are references to parent scopes in the current environment. Take the example above :π
var x = 1;
function demo() {
var x = 2
function demo2() {
console.log(x);
}
return demo2;
}
var h = demo();
h() / / 2
Copy the code
Here the h variable gets the variable in the parent scope and prints 2. In the current environment, there is a reference to Demo2, which references both the Window Demo and its scope. So Demo2 can access variables in the demo scope.
Question? Do only return functions produce closures? β
Getting back to the essence of closures: just make the reference to the parent scope exist so we can do this π
var demo2;
function demo() {
var x = 2
demo2 = function () {
console.log(x);
}
}
demo();
demo2() / / 2
Copy the code
Now demo2 has access to the window demo and its scope. So when demo2 searches for variable x, it will search up step by step. When it finds identifier in the nearest demo scope, it will return the result and output 2.
π€, where the external variable demo2 has a reference to the parent scope, produces a closure that changes form but remains essentially the same.
Closure representation π€€
Understanding the essence, we start from the real scene, where can reflect the existence of closures β
1οΈ one returns a function, an example has been given above
2οΈ transfer as a function parameter
var a = 1;
function foo(){
var a = 2;
function baz(){
console.log(a);
}
bar(baz);
}
function bar(fn){
// This is the closure
fn();
}
// Print 2 instead of 1
foo();
Copy the code
3οΈ on timers, event listeners, Ajax requests, cross-window communication, Web Workers or any asynchronism, as long as the callbacks are used, they are actually using closures
The following closures hold only the window and the current scope.
/ / timer
setTimeout(function timeHandler(){
console.log('2222'); },100)
// Event listener
$('#div').click(function(){
console.log('DIV Click');
})
Copy the code
4οΈ discount (immediate execution of function expression) create closure that stores the global scope window and the scope of the current function, so global variables can be allowed.
var x = 22;
(function IIFE(){
/ / output 22
console.log(x); }) ();Copy the code
Condition of generation
1οΈ retail function nesting
2οΈ internal function references data of external function (variable/function)
Destruction of closure
When it comes to closure destruction, the first thing to talk about is V8’s garbage collection mechanism
V8 garbage collection, I think I’ll start a new chapter about it at π€
Let’s talk about the garbage collection mechanism:
In javascript, if an object is no longer referenced, then the object is garbage collected. If two objects reference each other and are no longer referenced by a third party, then the two referenced objects are also reclaimed
π Simply put, if a reference object is not referenced,V8’s garbage collection mechanism destroys it, and the closure carries the scope of the function that contains it, thus consuming more memory than other functions. Therefore, you can manually de-reference anonymous functions to free up memory.
The disadvantage is to generate multiple private scopes (heap memory) that are not destroyed. In addition to the performance impact, it can be dangerous if the currently saved closure, or its parent scope, has HTML elements π«
Pay attention to
Closures cause variables in a function to be stored in memory, which is expensive, so don’t abuse closures because they can cause performance problems for web pages and, in IE, memory leaks. The solution is to remove all unused local variables before exiting the function.
Closures change the values of variables inside the parent function, outside the parent function. So, if you use a parent function as an object, a closure as its Public Method, and internal variables as its private values, be careful not to arbitrarily change the values of the parent function’s internal variables.
Of course, the proper use of closures can also solve a lot of problems, I think the idea of functional programming must be associated with closures.
For example, higher-order functions π€ Are currified
conclusion
- π― There are references to parent scopes in the current environment
- Referenced variables are not destroyed until the closure is destroyed
- Closures generate private scopes and consume a lot of memory, so do not abuse closures. For reference types, stored in heap memory can cause memory leaks, especially if the parent scope of a closure contains HTML elements, which can be dangerous π«
- Closures carry the scope of the function that contains them and therefore take up more memory than other functions. Therefore, you can manually de-reference anonymous functions to free up memory.
- Closure application scenarios: modularization and Currization
reference
Discover the power of closures in JavaScript
Ruan Yifeng closure
The underlying mechanics of JavaScript closures
Discover the power of closures in JavaScript
Diagram scopes and closures