Closure details for Javascript

  • 2020-05-10 17:37:28
  • OfStack

Introduction: or an introductory article. There are several very important language features in Javascript -- objects, prototype inheritance, closures. Among them, closures are a new language feature for programmers who use the traditional static language C/C++. This article begins with an example to introduce the language features of the Javascript closure, combined with the 1 point ECMAScript language specification to give the reader a deeper understanding of the closure.

Note: this article is an introductory article, the example material is arranged in the network, if you are a master, welcome to put forward technical Suggestions and comments on the article. This article is about Javascript. I don't want to make a language comparison. If you are not comfortable with Javascript, please make a detour.

What is a closure
What is a closure ? The closure is Closure, a new feature not available in static languages. But closures are nothing too complex to understand. In short, they are:

A closure is simply a collection of local variables that persist after the function returns.
Closures are the "stacks" of functions that are not released after the function returns, and we can also understand that these function stacks are not allocated on the stack but on the heap
A closure occurs when another function is defined within one function
The second definition above is the first complement, extracting the subject-predicate object of the first definition -- a closure is a collection of 'local variables' of a function. Only this local variable can be accessed after the function returns. (this is not an official definition, but it should make it easier for you to understand closures.)

As local variables can be accessed by code within functions, this is no different from static languages. The difference with closures is that local variables can still be accessed by code outside the function after execution. This means that the function must either return a "reference" to the closure or assign the "reference" to an external variable to ensure that the local variable in the closure is accessed by the external code. Of course, the entity that contains this reference should be an object, because in Javascript all but the basic types are objects. Unfortunately, ECMAScript does not provide the associated members and methods to access local variables in closures. In ECMAScript, however, the internal functions defined in the function object (inner function) are local variables that can be accessed directly from the external functions, and with this mechanism, the closure can be accessed in the following manner.


function greeting(name) {
    var text = 'Hello ' + name; // local variable
    // Each time it is called, the closure is generated and an internal function object is returned to the caller
    return function() { alert(text); }
}
var sayHello=greeting("Closure");
sayHello()  // Local variables are accessed through closures text

The result of the above code is: Hello Closure, because the sayHello() function still has access to the local variable text defined within the greeting function after it has finished executing.

Okay, so that's the effect of closures in Javascript. There are various scenarios and patterns for closures in Javascript, such as Singleton, Power, Constructor, Javascript, Javascript, Javascript, Constructor, Javascript, Javascript, Javascript, Constructor, Javascript, Javascript, Javascript, Javascript, Javascript

The ECMAScript closure model
How exactly does ECMAScript implement closures? If you want to know more about dear friends, you can obtain the ECMAScript specification for research. I will only make a brief explanation here, which is also from the network.

When the functions of ECMAscript's script are run, each function association has an execution context scenario (Execution Context), which consists of three parts

Grammar environment (The LexicalEnvironment)
Variable environment (The VariableEnvironment)
this binding
The third point, the this binding, has nothing to do with closures and is not discussed in this article. A variable identifier used in a grammar environment for parsing the execution of a function. We can think of the grammar environment as an object that contains two important components, the environment record (Enviroment Recode), and the external reference (pointer). The environment record contains local and parameter variables that contain the internal declaration of the function, and the external reference points to the context execution scenario of the external function object. This reference value is NULL in the global context scenario. Such a data structure forms a one-way linked list, with each reference pointing to the outer context scenario.

For example, the closure model in our example above should look like this: the sayHello function is at the lowest level, the upper level is the greeting function, and the outermost layer is the global scenario. Therefore, when sayHello is called, sayHello will find the value of local variable text through the context scene. Therefore, the function of "Hello Closure" variable environment (The VariableEnvironment) and grammar environment is basically similar in the dialog box on the screen. For specific differences, please refer to the specification document of ECMAScript.

The sample column of the closure
Earlier I got a general idea of what an Javascript closure is and how it is implemented in Javascript. To help you understand closures more deeply, let's look at some examples for 1. Here are five examples from JavaScript Closures For Dummies(mirror). Example 1: local variables in closures are references, not copies


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 pop up to 667 instead of 666.

Example 2: multiple function bindings are bound to the same closure because they are defined in the same function.


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(); // for 3 Three global variable assignments
gAlertNumber(); //666
gIncreaseNumber();
gAlertNumber(); // 667
gSetNumber(12);//
gAlertNumber();//12

Example 3: when assigning functions in a loop, these functions bind to the same closure


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 result of testList is that the item3 undefined window pops up three times, because these three functions bind to the same closure, and the value of item is the result of the last calculation. However, when i breaks out of the loop, the value of i is 4, so the result of list[4] is undefined.

Example 4: all local variables of an external function are inside a closure, even if the variable is declared after the internal function definition.


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 result is a popup 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 a function is called


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 closures
Singleton sheet:


var singleton = function () {
    var privateVariable;
    function privateFunction(x) {
        ...privateVariable...
    }
 
    return {
        firstMethod: function (a, b) {
            ...privateVariable...
        },
        secondMethod: function (c) {
            ...privateFunction()...
        }
    };
}();

This singleton is implemented through a closure. The closure completes the encapsulation of private members and methods. The anonymous main function returns an object. The object contains two methods, method 1 can be a method private variable, and method 2 can query an internal private function. Note that the '()' at the end of the anonymous main function does not produce singleton without this '()'. Because anonymous functions can only return 1-only objects and cannot be called elsewhere. This is how you generate singletons using closures.


Related articles: