Understanding of closures
How to generate closures?
- Closure occurs when a nested inner (child) function references a variable (function) of a nested outer (parent) function.
What is a closure?
- Understanding 1: a closure is a nested internal function. For example, in the following example, the internal function fun2() is a closure
function fun1(){ var a = 'I am a variable defined by the parent element a'; var b = 'variable b' function fun2 (){//fun2() is an internal function, a closure console.log(a);//Variable a declared in parent function is used } fun2(); } fun1()//Call function fun1()
-
Understanding 2: through debug debugging, you can see that closures are objects containing variables (functions) of external functions referenced by internal functions.
-
From the mode, you can see that a Closure only displays variable a and no variable b. therefore, it can also be understood that a Closure is an object of a variable (function) of an external function referenced by an internal function.
-
Executing an internal function definition produces a closure (without calling the function)
Conditions for generating closures
- Function nesting
- The internal function references the data of the external function (variable / function)
Common closures
Take a function as the return value of another function
function fun1() { var a = 0; function fun2() { a++; console.log(a); } return fun2; } var f = fun1(); f();//1 f();//2 f();//3
be careful:
- This process produces only one closure
- Each call to f() is equivalent to one execution of fun2()
Pass a function as an argument to another function call
function show(msg, time) { setTimeout(function () { console.log(msg); }, time) } show("Novelty time", 1000); </script>
Function of closure
- Use variables inside the function to survive in memory after the function is executed (prolong the life cycle of local variables)
- Data (variable / function) that can be manipulated (read and write) outside the function to the inside of the function
For example, in the above example
function fun1() { var a = 0; function fun2() { a++; console.log(a); } return fun2; } var f = fun1(); f();//1 f();//2 f();//3
- In this example, variable a still exists in memory after the function is executed
- You can operate (read and write) the variable a in fun1() through closures.
Closure lifecycle
- Closure generation: a closure (not a call) is generated when the execution of the nested inner function definition is completed
- Closure death: when nested inner functions become garbage objects
function fun1() { //At this time, the closure has been generated (function promotion, internal function object has been established) var a = 0; function fun2() { a++; console.log(a); } return fun2; } var f = fun1(); f();//1 f();//2 f();//3 f = null;//Closure death (function objects containing closures become garbage objects)
Application of closures: defining JS modules
- js files with specific functions
- Encapsulate all data and functions inside a function (private)
- Expose only one object and function containing n methods
- The user of the module only needs to call the method through the exposed object of the module to realize the corresponding function
Custom module
- Here, first create a JS file named myModule.js. The code is as follows
function myModule() { //Private data var str = "Hello World!!!"; //Functions that manipulate data function showBig() { console.log("showBig():" + str.toUpperCase()); } function showSamll() { console.log("showSmall():" + str.toLowerCase()); } //Exposed objects (Methods for external use) return { showBig: showBig, showSamll: showSamll } }
- Then, the myModule.js file is referenced in the html file through the < script > tag
<script src="./myModule.js"></script> <script> var fn = myModule(); fn.showBig(); fn.showSmall(); </script>
effect:
Another way of writing:
Add methods directly to the window by using the immediate execution function
(function() { //Private data var str = "Hello World!!!"; //Functions that manipulate data function showBig() { console.log("showBig():" + str.toUpperCase()); } function showSmall() { console.log("showSmall():" + str.toLowerCase()); } //Exposed objects (Methods for external use) window.myModule = { showBig: showBig, showSmall: showSmall } })()
- Then, the myModule.js file is referenced in the html file through the < script > tag
<script src="./myModule.js"></script> <script> myModule.showBig(); myModule.showSmall(); </script>
Shortcomings and solutions of closures
shortcoming
- After the function is executed, the local variables in the function are not released, and the memory consumption time will become longer
- Easy to cause memory leakage
Memory overflow and leak
out of memory
- An error in the operation of a program
- When the program needs more memory than the remaining memory, a memory overflow error will be thrown
Memory leak
- The occupied memory was not released in time
- Excessive accumulation of memory leaks can easily lead to memory overflow
Common memory leaks
- Unexpected global variables. There is no need to use var, let and const declarations. Variables are used directly
function fn(){ a = new.Array(10000); } fn();
- Timers or callback functions that are not cleaned up in time
var time = setInterval(function(){//Do not clean after cycle timer console.log("Who else?"); },1000); //clearInterval(time);
- closure
function fun1() { var a = 0; function fun2() { a++; console.log(a); } return fun2; } var f = fun1(); f();//1 f();//2 f();//3 / / closures may cause memory leaks f = null;//Recycle closures -- > make internal functions garbage objects
resolvent
- Use closures as little as possible
- Timely release
Interview questions
Interview question 1
//Code snippet 1 var name = "The Window"; var Object = { name: "The Object", getNameFunc: function () { return function () { return this.name; }; } }; console.log(Object.getNameFunc()());// ? "The Window" //Code snippet 2 var name2 = "The Window"; var Object = { name2: "The Object", getNameFunc: function () { var that = this; return function () { return that.name2; }; } }; console.log(Object.getNameFunc()());// ? "The Object"
Resolution:
- There is no closure in code fragment 1, which is equivalent to the direct execution of the function. Therefore, this points to The Window and prints "The Window"
- In code fragment 2, the external function first declares that a variable saves this, and this points to Object, and then the internal function uses the external function variable that to generate a closure. The value in that saves The Object pointed to by this, so print "The Object"
Interview question 2
function fun(n, o){ console.log(o); return{ fun: function(m){ return fun(m, n); } } } var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined, ?, ?, ? console.log("--------------------"); var b = fun(0).fun(1).fun(2).fun(3);//undefined, ?, ?, ? console.log("--------------------"); var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined, ?, ?, ?
thinking
- First, find the variable that generates the closure, that is, n. each time you print the last generated closure, n. if no closure is generated, the print is undefined
- As follows:
var a = fun(0); //undefined, a closure n = 0 will be generated here; Therefore, 0 will be printed below a.fun(1); a.fun(2); a.fun(3);//0, 0, 0 console.log("--------------------"); var b = fun(0).fun(1).fun(2).fun(3);//undefined, 0, 1, 2 console.log("--------------------"); var c = fun(0).fun(1);//undefined, 0, closure n = 1 will be generated here; c.fun(2);//one The closure n = 2 will be generated here, but it will be garbage collected c.fun(3);//one The closure n = 3 will be generated here, but it will be garbage collected