Go: In-depth understanding of JavaScript closure Concepts

Source: Internet
Author: User
Tags variable scope

Closures have always given a mysterious, advanced sense to programmers, including JavaScript programmers, and in fact, the concept of closures is not a hard-to-understand knowledge in functional programming languages. If you understand the basic concepts of scope and function as independent objects, it is quite a good idea to understand the concept of closure and apply it in practical programming practice.

In the case of DOM handling, most programmers are already using closures without realizing it, and in such cases, the problem with the JavaScript engine embedded in the browser may cause a memory leak, which is often confused by the programmer's own debugging.

Use simple statements to describe the concept of closures in javascript: Because in JavaScript, a function is an object, an object is a collection of properties, and a property's value can be an object, it is natural to define a function within a function, if the function inner is declared inside the function func, Then call inner outside of the function, and the process produces a closure.

Characteristics of closures
Let's take a look at an example where it's hard to find a reason if you don't understand the JavaScript features:

varOutter = []; functionclousetest () {varArray = ["One", "one", "three", "four"];  for(vari = 0; I < array.length;i++){         varx = {}; X.no=i; X.text=Array[i]; X.invoke=function() {print (i);      } outter.push (x); }  }     //Call this functionclousetest (); Print (outter[0].invoke ()); Print (outter[1].invoke ()); Print (outter[2].invoke ()); Print (outter[3].invoke ());


What is the result of the operation? Many beginners may come up with this answer:
0
1
2
3

However, to run this program, the results are as follows:
4
4
4
4

In fact, at each iteration, such a statement x.invoke = function () {print (i);} is not executed, just constructs a function body as "print (i);" Function object, that's all. When i=4, the iteration stops, the external function returns, and when the Outter[0].invoke () is called again, the value of I is still 4, so that the invoke of each element in the Outter array returns the value of I: 4.

How to solve this problem? We can declare an anonymous function and execute it immediately:
var outter = [];

function ClouseTest2 () {      var array = ["One", "one", "three", "four"];        for (var i = 0; i < array.length;i++) {         var x = {};          = i;          = Array[i];          function (NO) {             returnfunction() {                print (no);             }         } (i);         Outter.push (x);      }    }     ClouseTest2 ();  


 
In this example, When we assign a value to X.invoke, we run a function that returns a function and execute it immediately, so that every time the iterator is X.invoke, it executes the following statement:
//x == 0  
X.invoke = function () {print (0);}   
//x == 1  
X.invoke = function () {print (1);}   
//x == 2  
X.invoke = function () {print (2);}   
//x == 3  
X.invoke = function () {print (3);}   
This will give you the right result. Closures allow you to reference variables that exist in external functions. However, instead of using the value of the variable when it was created, it uses the last value of the variable in the outer function.
 
purpose of the closure
Now that the concept of closures is clear, let's look at the purpose of closures. In fact, we can do a lot of things by using closures. such as simulating object-oriented code style, more elegant, more concise expression of code, in some ways to improve the efficiency of code execution.
 
Anonymous self-executing function
The example in the previous section is, in fact, a use of closures, and according to the foregoing, all variables, if not added to the VAR keyword, will be added to the properties of the global object by default. , there are a number of drawbacks to adding a temporary variable to a global object, such as: Other functions may misuse these variables, causing the global object to be too large to affect access speed (because the value of the variable is to be traversed from the prototype chain). In addition to using the VAR keyword every time, we often encounter situations where a function needs to be executed only once and its internal variables are not maintained, such as the initialization of the UI, then we can use closures:

var datamodel = {      table: [],      tree: {}  };     (function(DM) {      for (var i = 0; i < dm.table.rows;i++) {          var row = dm.table.rows[i];           for (var j = 0; j < row.cells; i++) {             Drawcell (i, j);         }      }            // build Dm.tree    }) (Datamodel);


We create an anonymous function and execute it immediately, because the external cannot reference its internal variables, so it will be released soon after execution, the key is that this mechanism does not pollute the global object.

Cache
Another example, imagine that we have a processing time of the function object, each call will take a long time, then we need to store the computed value, when the function is called, first in the cache to find, if not found, then calculate, then update the cache and return the value, if found, Return directly to the value you are looking for. Closures can do this because it does not release external references, so values inside the function can be preserved.

varCachedsearchbox = (function(){      varCache ={}, Count= []; return{attachsearchbox:function(DSID) {if(DsidinchCache) {//If the result is in the cache              returnCACHE[DSID];//directly returns objects in the cache           }             varFSB =NewUikit.webctrl.SearchBox (DSID);//NewCACHE[DSID] = FSB;//Update Cache           if(Count.length > 100) {//the size of the positive cache <=100              DeleteCache[count.shift ()]; }             returnFSB; }, Clearsearchbox:function(DSID) {if(Dsidinchcache)               {cache[dsid].clearselection ();  }         }      };  })(); 



Cachedsearchbox.attachsearchbox ("input1");
Thus, when we call Cachedsearchbox.attachserachbox ("INPUT1") for the second time, we can take the object from the cache without having to create a new SearchBox object.

Implementing encapsulation
You can start by looking at an example of encapsulation, where you cannot access the variables inside of a person, but by providing closures:

<strong>varperson =function(){      //variable scope is inside function, external unreachable    varName = "Default"; return{getName:function(){             returnname; }, SetName:function(newName) {name=NewName;     }      }  }(); Print (person.name);//direct access with a result of undefinedprint (Person.getname ()); Person.setname ("Abruzzi"); Print (Person.getname ());</strong>The results are as follows: undefineddefaultAbruzzi


Another important use of closures is the implementation of object-oriented objects, the traditional object language provides the template mechanism of the class, so that different objects (instances of the class) have independent Members and state, non-interference. Although there is no such mechanism in JavaScript, we can simulate such a mechanism by using closures. Or in the above example:

functionPerson () {varName = "Default"; return{getName:function(){             returnname; }, SetName:function(newName) {name=NewName;        }      }  }; varJohn =Person ();  Print (John.getname ()); John.setname ("John");     Print (John.getname ()); varJack =Person ();  Print (Jack.getname ()); Jack.setname ("Jack"); Print (Jack.getname ());

runs as follows:
Default
John
Default
Jack
This code shows that Both John and Jack can be referred to as instances of the person class, because these two instances have independent, non-impact access to the name member.
 
In fact, in the functional design of the program, there will be a lot of closure, we will discuss the functional programming in the eighth chapter, where we will again explore the role of closures.
 
should be aware of issues
memory leaks
in different JavaScript interpreter implementations, the use of closures can cause memory leaks due to the interpreter's own flaws, and memory leaks are a serious problem. Can seriously affect the browser's responsiveness, reduce the user experience, and even cause the browser to be unresponsive and so on.
 
The JavaScript interpreter has a garbage collection mechanism, generally in the form of reference counts, and if an object has a reference count of zero, the garbage collection mechanism recycles it, which is automatic. However, with the concept of closures, this process becomes complex, in closures, because local variables may need to be used at some point in the future, so the garbage collection mechanism does not process these externally referenced local variables, and if there is a circular reference, object A refers to B,b reference C, and C refers to a , which causes the garbage collection mechanism to draw a conclusion that its reference count is nonzero, causing a memory leak.
 
Context Reference
about this we've discussed this before, it represents a reference to the calling object, and in the closure, the most error-prone place is the misuse of this. In front-end JavaScript development, a common mistake is to mistake this analogy for other external local variables:

$ (function() {      var con = $ ("Div#panel");       this. id = "Content";      Con.click (function() {         alert (this. id);   panel    }  ) ;


What value does the alert (this.id) here refer to? Many developers may make the wrong decision based on the concept of closures:
content
 
The reason is that the this.id display is assigned to content, and in the click Callback, The resulting closure is referenced to This.id, so the return value is content. In fact, the alert will pop up "panel", the reason is this here, although the closure can refer to local variables, but when it comes to this, the situation is somewhat subtle, because the invocation of the object, so that when the closure is called ( When this panel's Click event occurs), here the This refers to con, the jquery object. The this.id =  "content" in the anonymous function is the operation of the anonymous function itself. Two this reference is not the same object.
         
If you want to access this value in an event handler, we have to make some changes:  

$ (function() {      var con = $ ("Div#panel");       this. id = "Content";       var  This ;      Con.click (function() {         alert (self.id); // content       });  });  



In this way, we are saving a reference to the external local variable self in the event handler, not this. This technique is used in practical applications, and we discuss it in detail in the sections that are behind it. For more information on closures, we will discuss them in detail in the Nineth chapter, including the discussion of "closures" in other imperative languages, the application of closures in actual projects, and so on.

Original address: http://bbs.csdn.net/topics/390692863


Go: In-depth understanding of JavaScript closure Concepts

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.