Home >Web Front-end >JS Tutorial >Detailed explanation of closures in Javascript_Basic knowledge

Detailed explanation of closures in Javascript_Basic knowledge

WBOY
WBOYOriginal
2016-05-16 16:24:21937browse

Foreword: This is still an introductory article. There are several very important language features in Javascript - objects, prototypal inheritance, and closures. Among them, closure is a new language feature for programmers who use the traditional static language C/C. This article will start with examples to introduce the language features of Javascript closures, and combine it with some ECMAScript language specifications to enable readers to have a deeper understanding of closures.

Note: This article is an introductory article. The example materials are compiled from the Internet. If you are an expert, you are welcome to provide technical suggestions and opinions on the article. This article discusses Javascript. I don’t want to do a language comparison. If you are naturally uncomfortable with Javascript, please take a detour.

What is closure
What is a closure? Closure is Closure, which is a new feature that static languages ​​do not have. But closure is not something too complicated to understand. In short, closure is:

A closure is a collection of local variables of a function, but these local variables will continue to exist after the function returns.
Closure means that the "stack" of a function is not released after the function returns. We can also understand that these function stacks are not allocated on the stack but on the heap
When defining another function within a function, a closure will be generated
The second definition above is the first supplementary explanation, extracting the subject, predicate and object of the first definition - closure is the set of 'local variables' of the function. It's just that this local variable can be accessed after the function returns. (This is not an official definition, but this definition should be more helpful for you to understand closures)

As a local variable, it can be accessed by the code within the function. This is no different from a static language. The difference with closures is that local variables can still be accessed by code outside the function after the function execution ends. This means that the function must return a "reference" pointing to the closure, or assign this "reference" to an external variable to ensure that the local variables in the closure can be accessed by external code. Of course, the entity containing this reference should be an object, because in Javascript, except for basic types, everything else is an object. Unfortunately, ECMAScript does not provide relevant members and methods to access local variables in closures. But in ECMAScript, the inner function (inner function) defined in the function object can directly access the local variables of the external function. Through this mechanism, we can complete access to the closure in the following way.

Copy code The code is as follows:

function greeting(name) {
var text = 'Hello ' name; // local variable
// Each time it is called, a closure is generated and the internal function object is returned to the caller
Return function() { alert(text); }
}
var sayHello=greeting("Closure");
sayHello() // The local variable text
is accessed through the closure

The execution result of the above code is: Hello Closure, because the sayHello() function can still access the local variable text defined within it after the greeting function is executed.

Okay, this is the legendary effect of closures. Closures have a variety of application scenarios and modes in Javascript, such as Singleton, Power Constructor and other Javascript modes that are inseparable from the use of closures.

ECMAScript Closure Model
How does ECMAScript implement closures? Those who want to learn more can obtain the ECMAScript specification for research. I will only give a simple explanation here, and the content also comes from the Internet.

When the function of the ECMAscript script is running, each function association has an execution context scene (Execution Context). This execution context scene contains three parts

The LexicalEnvironment
The VariableEnvironment
this binding
The third point, this binding, has nothing to do with closures and will not be discussed in this article. The grammar environment is used to parse variable identifiers used during function execution. We can imagine the grammar environment as an object, which contains two important components, environment record (Enviroment Recode), and external reference (pointer). The environment record contains local variables and parameter variables declared inside the function, and external references point to the context execution scenario of the external function object. The value of this reference in the global context scene is NULL. Such a data structure forms a one-way linked list, with each reference pointing to the outer context scene.

For example, the closure model of our example above should be like this. The sayHello function is at the bottom layer, the upper layer is the greeting function, and the outermost layer is the global scene. As shown below: So when sayHello is called, sayHello will find the value of the local variable text through the context scene, so "Hello Closure" is displayed in the dialog box on the screen. The functions of the variable environment (The VariableEnvironment) and the grammar environment are basically similar. Please refer to the ECMAScript specification document for specific differences.

Sample sequence of closures
Previously, I roughly understood what Javascript closures are and how closures are implemented in Javascript. Below we will help you understand closures more deeply through some examples. There are 5 examples below. The examples come from JavaScript Closures For Dummies (mirror). Example 1: Local variables in closures are references rather than copies

Copy code The code is as follows:

function say667() {
// Local variable that ends up within closure
var num = 666;
var sayAlert = function() { alert(num); }
num ;
Return sayAlert;
}

var sayAlert = say667();
sayAlert()

So the execution result should be 667 instead of 666.

Example 2: Multiple functions bind the same closure because they are defined in the same function.

Copy code The code is as follows:

function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gAlertNumber = function() { alert(num); }
gIncreaseNumber = function() { num ; }
gSetNumber = function(x) { num = x; }
}
setupSomeGlobals(); // Assign values ​​to three global variables
gAlertNumber(); //666
gIncreaseNumber();
gAlertNumber(); // 667
gSetNumber(12);//
gAlertNumber();//12

Example 3: When assigning functions in a loop, these functions will be bound to the same closure

Copy code The code is as follows:

function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i ) {
        var item = 'item' list[i];
result.push( function() {alert(item ' ' list[i])} );
}
Return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j ) {
            fnlist[j]();
}
}

The execution result of testList is that the item3 undefined window pops up three times, because these three functions are bound to the same closure, and the value of item is the last calculated result, but when i jumps out of the loop, the value of i is 4, so list The result of [4] is undefined.

Example 4: All local variables of the outer function are within the closure, even if this variable is declared after the inner function is defined.

Copy code The code is as follows:

function sayAlice() {
var sayAlert = function() { alert(alice); }
// Local variable that ends up within closure
var alice = 'Hello Alice';
Return sayAlert;
}
var helloAlice=sayAlice();
helloAlice();

The execution result is a pop-up window of "Hello Alice". Even if the local variable is declared after the function sayAlert, the local variable can still be accessed.

Example 5: Create a new closure every time the function is called

Copy code The code is as follows:

function newClosure(someNum, someRef) {
// Local variables that end up within closure
var num = someNum;
var anArray = [1,2,3];
var ref = someRef;
Return function(x) {
         num = x;
        anArray.push(num);
alert('num: ' num
          'nanArray ' anArray.toString()
          'nref.someVar ' ref.someVar);
}
}
closure1=newClosure(40,{someVar:'closure 1'});
closure2=newClosure(1000,{someVar:'closure 2'});

closure1(5); // num:45 anArray[1,2,3,45] ref:'someVar closure1'
closure2(-10);// num:990 anArray[1,2,3,990] ref:'someVar closure2'

Application of closure
Singleton:

Copy code The code is as follows:

var singleton = function () {
var privateVariable;
function privateFunction(x) {
           ...privateVariable...
}

Return {
         firstMethod: function (a, b) {
                  ...privateVariable...
},
secondMethod: function (c) {
                  ...privateFunction()...
}
};
}();

This singleton is implemented through closures. Encapsulation of private members and methods is completed through closures. The anonymous main function returns an object. The object contains two methods, method 1 can access private variables, and method 2 can access internal private functions. What needs attention is the '()' at the end of the anonymous main function. Without this '()', the singleton cannot be generated. Because anonymous functions can only return a unique object and cannot be called from other places. This is how to use closures to generate singletons.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn