JavaScript Closure example detailed _javascript tips

Source: Internet
Author: User
Tags closure instance method javascript closure example memory usage

First, charge

1, everything (reference type) is an object, the object is a collection of attributes.

2, a function is an object, but a function is not like an array-you can say that an array is a kind of object, because the array is like a subset of the object. But between functions and objects, it is not just a relationship that contains and is contained, the relationship between functions and objects is more complex, and there is even the logic of chicken eggs and eggs.

function Fn () {this.name = ' Wang Fu '; this.year = 1988;}
var fn1 = new Fn ();
var obj = {a:10, b:20}; equivalent to var obj = new Object ();
OBJ.A = 10;OBJ.B =;
var arr = [5, ' X ', true]; equivalent to var arr = new Array ();
Arr[0] = 5;arr[1] = ' x '; arr[2] = true;

An object is created by a function, but a function is another object.

3, each function has a property called prototype. The attribute value of this prototype is an object (a collection of attributes, again emphasized!). , the default is only a property called constructor, which points to the function itself.

4. Each object has a __proto__ property that points to the prototype of the function that created the object. This __proto__ is a hidden attribute, JavaScript does not want developers to use this attribute value, and some low version browsers do not even support this attribute value. obj.__proto__=== Object.prototype

Second, closures

1, the basic concept of closure

A function that has access to a variable in another function scope. Simply understood as "functions defined within a function" such as:

function Createcomparisonfunction (PropertyName) {return 
function (OBJECT1,OBJECT2) {//anonymous functions 
value1=object1[ PropertyName]; 
Value2=object2[propertyname]; 
if (value1<value2) { 
return-1; 
} else if (value1>value2) {return 
1; 
} else{return 
0; 
}} Create function 
var comparenames=createcomparisonfunction ("name"); 
Call function 
var result=comparenames ({name: "Nicolas"},{name: "Greg"}); 
Unbind a reference to an anonymous function (in order to free memory) 
Comparenames=null; 

(1). Benefits: Security of variables in the protection function, enhanced encapsulation, maintenance of a variable (cache) in memory; anonymous self-executing function; simulation of object-oriented programming.

(2). Scenario: Use closures instead of global variables, functions or other functions to access parameters within a function, wrapper-related functions, bind the Click event for a node, and use the value or node of the secondary loop in the event function, rather than the value or node of the last loop;

(3). Disadvantage: Resident memory, will increase memory usage, improper use can easily cause memory leaks, more importantly, improper use of closures will result in invalid memory production.

As long as there is a possibility of calling an intrinsic function, JavaScript needs to retain the referenced function. and the JavaScript runtime needs to track all the variables that refer to the internal function until the last variable is discarded, and the JavaScript garbage collector frees up the appropriate memory space. The variables defined by the parent function are in the scope chain of the child function, the child function is not destroyed, and all variables and functions in the scope chain are maintained and will not be destroyed.

2, closure of the use of the package

Closures have two uses, one is to facilitate the implementation of nested callback functions, and the second is to hide the details of the object.

For the former, Nodejs's programming style has been able to explain the problem, the latter is not visible to the local variables inside the function, but can provide access functions to access and modify the corresponding local variables, so as to achieve OO encapsulation intent.

(1), simple example

First from a classic error, there are several div on the page, we want to bind them to a onclick method, so we have the following code

<! DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 transitional//en" "Http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">  

Very simple function But it happens to be wrong, each alert out of the value is 4, simple modification is good

$ (document). Ready (function () { 
var spans = $ ("#divTest span"); 
for (var i = 0; i < spans.length i++) { 
(function (num) {//anonymous function expression 
Spans[i].onclick = function () { 
alert (num ); 
} 
}) (i);//execute immediately, and pass the value of I to num 
} 
});

The above code executes when the page is loaded, when I has a value of 4, the judgment condition does not set, the For loop executes, but because each span's OnClick method is at this time an intrinsic function, so I is closed the package reference, the memory cannot be destroyed, I the value will keep 4, It will not be reclaimed until the program changes it or if all the onclick functions are destroyed (by actively assigning the function to null or the page is unloaded). So every time we click on the span, the onclick function looks at the value of I (the scope chain is the reference), 4, and then alert us. The second way is to use an immediately executed function and create a layer of closure, the function declaration is placed in parentheses into the expression, followed by parentheses and brackets is called, and then the I when the argument passed, the function immediately execute, NUM save each time I value.

(2), internal function

Let's start with some basic knowledge about the internal functions. An intrinsic function is a function defined in another function. For example:

function Outerfn () { 
function Innerfn () {} 

INNERFN is an internal function that is wrapped in a OUTERFN scope. This means that calling INNERFN inside Outerfn is valid, and calling INNERFN outside of OUTERFN is not valid. The following code causes a JavaScript error:

function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
document.write ("Inner function<br/>"); 
} 
 

However, if you call INNERFN inside OUTERFN, you can run successfully:

function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
document.write ("Inner function<br/>"); 
} 
INNERFN (); 
} 

(3), The Great Escape

JavaScript allows developers to pass functions like any type of data, meaning that internal functions in JavaScript can escape the definition of their external functions.

There are many ways to escape, for example, you can assign an intrinsic function to a global variable:

var Globalvar; 
function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
document.write ("Inner function<br/>"); 
} 
Globalvar = INNERFN; 
} 
OUTERFN (); 

When OUTERFN is invoked, the global variable Globalvar is modified, when its reference becomes INNERFN, and then calls Globalvar and calls INNERFN. Calling INNERFN directly outside the OUTERFN will still result in an error, because the intrinsic function, although it escaped by saving the reference in a global variable, is still the name of the function in the scope of the OUTERFN.
You can also get an internal function reference by the return value of the parent function

function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
document.write ("Inner function<br/>"); 
} 
return INNERFN; 
} 
var fnref = OUTERFN (); 

Instead of modifying the global variable inside the OUTERFN, a reference to INNERFN is returned from the OUTERFN. This reference can be obtained by invoking OUTERFN, and the reference may be saved in a variable.

The fact that the internal function can be invoked by reference even if it leaves the function scope means that JavaScript needs to retain the referenced function whenever there is a possibility of invoking an intrinsic function. and the JavaScript runtime needs to track all the variables that refer to the internal function until the last variable is discarded, and the JavaScript garbage collector frees up the appropriate memory space.

After half a day, I finally had a relationship with the closure, a closure is a function that has permission to access a variable of another function, and the common way to create a closure is to create another function inside a function, which is the internal function we're talking about, so it's not just nonsense, it's also closure related.

(4) Scope of the variable

Internal functions can also have their own variables, which are limited to the scope of the internal function:

function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
var innervar = 0; 
innervar++; 
document.write ("Inner function\t"); 
document.write ("Innervar =" +innervar+ "<br/>"); 
} 
return INNERFN; 
} 
var fnref = Outerfn (); 
Fnref (); 
Fnref (); 
var FnRef2 = Outerfn (); 
FnRef2 (); 

Whenever this intrinsic function is invoked by reference or otherwise, a new Innervar variable is created, followed by 1, and the final display

Outer function
Inner function Innervar = 1
Inner function Innervar = 1
Outer function
Inner function i Nnervar = 1
Inner function Innervar = 1

Internal functions can also refer to global variables like other functions:

var globalvar = 0; 
function Outerfn () { 
document.write ("Outer function<br/>"); 
function Innerfn () { 
globalvar++; 
document.write ("Inner function\t"); 
document.write ("Globalvar =" + Globalvar + "<br/>"); 
} 
return INNERFN; 
} 
var fnref = Outerfn (); 
Fnref (); 
Fnref (); 
var FnRef2 = Outerfn (); 
FnRef2 (); 

The value of this global variable is continuously incremented each time the internal function is invoked:

Outer function
Inner function Globalvar = 1
Inner function Globalvar = 2
Outer function
Inner functio n Globalvar = 3
Inner function Globalvar = 4

But what if the variable is a local variable of the parent function? Because intrinsic functions refer to the scope of the parent function (interested in understanding the scope chain and the knowledge of the active object), internal functions can also refer to these variables

function Outerfn () { 
var outervar = 0; 
document.write ("Outer function<br/>"); 
function Innerfn () { 
outervar++; 
document.write ("Inner function\t"); 
document.write ("Outervar =" + Outervar + "<br/>"); 
} 
return INNERFN; 
} 
var fnref = Outerfn (); 
Fnref (); 
Fnref (); 
var FnRef2 = Outerfn (); 
FnRef2 (); 

This time the result is very interesting, perhaps or to our surprise

Outer function
Inner function Outervar = 1
Inner function Outervar = 2
Outer function
Inner function o Utervar = 1
Inner function Outervar = 2

What we see is the effect of the previous two cases, the INNERFN will be incremented independently by each reference invocation Outervar. This means that the second call OUTERFN does not continue to follow the Outervar value, but instead creates and binds a new Outervar instance in the scope of the second function call, with two counters completely unrelated.

When an intrinsic function is referenced outside the scope that defines it, a closure of the intrinsic function is created. In this case, we say that neither the internal function local variable nor its parameter is a free variable, and that the calling environment of the external function is a closed-closure environment. Essentially, if an intrinsic function references a variable in an external function, it is tantamount to authorizing the variable to be deferred. Therefore, when external function calls are complete, the memory of these variables is not freed (the last value is saved), and closures still need to be used.

(5), the interaction between closures

When multiple internal functions are present, unexpected closures are likely to occur. We define an increment function, the increment of this function is 2

function Outerfn () { 
var outervar = 0; 
document.write ("Outer function<br/>"); 
function InnerFn1 () { 
outervar++; 
document.write ("Inner function 1\t"); 
document.write ("Outervar =" + Outervar + "<br/>"); 
} 
function innerFn2 () { 
Outervar + + 2; 
document.write ("Inner function 2\t"); 
document.write ("Outervar =" + Outervar + "<br/>"); 
} 
return {"fn1": InnerFn1, "fn2": InnerFn2}; 
} 
var fnref = Outerfn (); 
Fnref.fn1 (); 
Fnref.fn2 (); 
Fnref.fn1 (); 
var FnRef2 = Outerfn (); 
Fnref2.fn1 (); 
Fnref2.fn2 (); 

We map a reference that returns two internal functions that can be invoked by the returned reference, resulting in the following:

Outer function
Inner function 1 outervar = 1
Inner function 2 Outervar = 3
Inner function 1 Outervar = 4
O uter function
Inner function 1 outervar = 1
Inner function 2 Outervar = 3
Inner function 1 Outervar = 4

InnerFn1 and InnerFn2 refer to the same local variable, so they share a closed environment. When innerFn1 for Outervar increments for a while, long absence innerFn2 set a new threshold for Outervar, and vice versa. We also see that subsequent calls to OUTERFN also create new instances of these closures. It also creates a new enclosing environment, essentially creating a new object in which the free variable is the instance variable of the object, and the closure is the instance method of the object, and the variables are private, Because these variables cannot be directly referenced outside the scope that encapsulates them, this ensures the exclusivity of object-oriented data.

3. Simulate block-level scopes

JavaScript is a functional scope (function scope) and does not have a block-level scope. Regardless of where the variable in the function is declared, it is visible to the entire function, that is, all variables declared in the JavaScript function are advanced to the top of the function body, only the advance variable declaration, and the assignment of the variable remains in the original position.

Anonymous functions can be used to mimic block-level scopes to prevent variables being declared as global variables in advance, and as the syntax for anonymous functions that block-level scopes, often called private scopes, are as follows:

(function () {
//here is block-level scope
}) ();

For example:

function output (count) { 
(function () {for 
(var i=0;i<count;i++) { 
alert (i); 
} 
}) (); 
alert (i); 
} 

Any variables defined in an anonymous function are destroyed at the end of execution. Therefore, the variable I can only be used in a loop and is destroyed after use.

4. Private variables

We refer to public methods that have access to private variables and private functions as privileged methods.

(1), defining the privileged method in the constructor

function person (name) { 
//name is a private variable 
this.getname=function () {//Privileged method return 
name; 
This.setname=function (value) {//Privileged method 
Name=value 
}; 
} 
var person=new person ("Zoumiao"); 
Alert (Person.getname ()); 
Person.setname ("Zouzou"); 
Alert (Person.getname ()); 
var person1=new person ("Zou"); 
Alert (Person1.getname ());//"Zou" 

The disadvantage of defining a privileged method in a constructor is that you must use a constructor pattern to do this, and the disadvantage of the constructor pattern is that it creates the same set of new methods for each instance, and the use of static private variables to implement the privileged method can avoid this problem.

(2), static private variables

By defining a private variable or function in a private scope, you can also create a privileged method with the following basic pattern:

(function () { 
var name= ';//static, shared by all instances property 
Person=function (value) {//Global constructor 
name=value; 
} 
Person.prototype.getname=function () {//Public/Privileged method return 
name; 
} 
Person.prototype.setname=function (value) {//Public/privileged Method 
Name=value; 
} 
}) (); 
var person=new person ("Zoumiao"); 
Alert (Person.getname ()); 
Person.setname ("Zouzou"); 
Alert (Person.getname ()); 
var person1=new person ("Zou"); 
Alert (Person1.getname ());//"Zou" 

The difference between this pattern and the method of defining the privilege in the constructor is that private variables and functions are shared by instances.

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.