Javascript scopes and closures use detail

  • 2020-03-30 02:41:39
  • OfStack

The nesting of scopes forms a chain of scopes, and the nesting of functions forms closures. Closures and scope chains are one of the important features that distinguish JavaScript from other languages.

scope
There are two types of scope in JavaScript: function scope and global scope.

The variables declared in a function have the same scope as the arguments to that function. A simple example of a function scope:


function foo() {
    var bar = 1;
    {
        var bar = 2;
    }
    return bar; // 2
}

Unlike other block-scoped languages such as C, this will always return 2.

Global scope, which can be interpreted by the browser as a window object (node. js is global) :


var bar = 1;
function foo() {}
alert(window.bar); // 1
alert(window.foo); // "function foo() {}"

Both the bar and the function foo are global scope variables, both of which are properties of the window.

The scope chain
When a variable is accessed in JavaScript, it starts with local variables and parameters, traversing the scope level up to the global scope.


var scope = 0, zero = "global-scope";
(function(){
    var scope = 1, one = "scope-1";
    (function(){
        var scope = 2, two = "scope-2";
        (function(){
            var scope = 3, three = "scope-3";
            // scope-3 scope-2 scope-1 global-scope
            console.log([three, two, one, zero].join(" "));
            console.log(scope); // 3
        })();
        console.log(typeof three); // undefined
        console.log(scope); // 2
    })();
    console.log(typeof two); // undefined
    console.log(scope); // 1
})();
console.log(typeof one); // undefined
console.log(scope); // 0

In the innermost function, each variable can be traversed and output step by step. In the penultimate function, the variable three cannot be traversed, so the output is undefined.

For example, when you are about to spend some money to buy something, you will feel your wallet first. If you have no money, you can ask your father for it. . And when your dad doesn't have the money to buy something, he doesn't come to you for it.

closure
Within a function, define another function, called function nesting. The nesting of functions forms a closure.

Closures are complementary to scope chains, and the nesting of functions results in multiple scopes of the chain relationship and also a closure.


function bind(func, target) {
    return function() {
        func.apply(target, arguments);
    };
}

So what about closures?

An external function cannot access an embedded function
An external function cannot access the arguments and variables of an embedded function
Inline functions can access the arguments and variables of external functions
To put it another way: an inline function contains the scope of an external function
Let's take a look at the example of a scoped chain, this time from the point of view of a closure:

The same code at the page code block index 2

The innermost function has access to all variables defined internally and externally. The function in the penultimate layer cannot access the variables in the innermost layer. Meanwhile, the assignment operation of scope = 3 in the innermost layer does not affect the variables with the same name outside it.

Another way to think about closures:

Each time an external function is called, an embedded function is created
When it is created, the scope of the external function (including any local variables, parameters, and so on) becomes part of the internal state of each embedded function object, even after the external function is executed and exits
Here's an example:


var i, list = [];
for (i = 0; i < 2; i += 1) {
    list.push(function(){
        console.log(i);
    });
}
list.forEach(function(func){
  func();
});

We'll get two "2" instead of the expected "1" and "2", because both functions in the list access the same variable I in their upper scope.

Let's change the code to use closures to solve this problem:


var i, list = [];
for (i = 0; i < 2; i += 1) {
    list.push((function(j){
        return function(){
            console.log(j);
        };
    })(i));
}
list.forEach(function(func){
  func();
});

The outer "execute now function" receives a parameter variable I in the form of parameter j within its function, which points to the same reference as the name j in the returned inner function. After the outer function executes and exits, the parameter j (at this point its current value is I) is saved as part of the state of its inner function.


Related articles: