Scope Chain + Closures

scope chain

First look at this code:

var a = '喜羊羊';
function A(){
    console.log(a);
    a = '美羊羊';
    function B(){
        console.log(a);
    }
    B();
}
A();
复制代码

There is no doubt that the result here must be what we thought of printing Pleasant Goat first, and then printing Beautiful Goat. Because of the scope chain, if the current layer is not found, then go to the upper level of the current layer to find it.

Then look at this


function bar() {
    console.log(myName)
}
function foo() {
    var myName = "极客邦"
    bar()
}
var myName = "极客时间"
foo()
复制代码

Does it feel like printing geeks? If so, then congratulations, you fell into the pit. (还不赶快爬起来,补一补作用域链的知识).

Why is printing not Geek State but Geek Time?

既然问题出现在了对作用域链的理解上,那么就再回到作用域链的定义上吧。

In fact, in the variable environment of each execution context, an external reference is included to point to the external execution context. We call this external reference outer.

For example, when the above code looks for myNamea variable, if it is not found in the current variable environment, the JavaScript engine will continue to look for it in the execution context pointed to by outer

For an intuitive understanding, you can look at the following picture:

Seeing this picture, I guess you are wondering again, why bardoes the outer in the execution context created by the function point to the global? ?

Hahaha, lexical scope is involved here

lexical scope

Lexical scope means that the scope is determined by the position of the function declaration in the code, so the lexical scope is a static scope, through which it is possible to predict how the code looks for identifiers during execution.

This may not be easy to understand, you can see the picture below:

It can be seen from the figure that the lexical scope is 代码的位置determined by the basis, where mainthe function contains barthe function, and the function bar contains foothe function, because the JavaScript scope chain is determined by the lexical scope, so the order of the entire lexical scope chain is :foo function scope—>bar function scope—>main function scope—>global scope.

Now that we understand lexical scope, let's go back to the question just now.

Why does the outer in the execution context created by the bar function point to the global

This is because according to the lexical scope, and the lexical scope is based on the position of the code, and the position of the bar function code is wrapped in the global, and the B function in the example of Pleasant Goat is in the environment of the A function, so it will cause Their lexical scope chains are different, which leads to different function scope chains.

That's why we have that sentence词法作用域是代码编译阶段就决定好的,和函数是怎么调用的没有关系。

That is, it is only related to the location of the code, and it has nothing to do with how the function is called directly

Closure

This is an old-fashioned question, and this time I will understand it from a deeper perspective.

Take a look at the following code:


function foo() {
    var myName = "极客时间"
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName:function(){
            console.log(test1)
            return myName
        },
        setName:function(newName){
            myName = newName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName("极客邦")
bar.getName()
console.log(bar.getName())
复制代码

There is nothing wrong with this code at first glance, but there is a detail here that many people will overlook.

When foo() is executed and the return value is given bar, the foo function will be popped from the call stack, and the variables will be recycled. Now that the variables are recycled, bar.setName()where do these calling methods come from? ?

The situation after foo is executed can refer to the following figure:

As can be seen from the figure above, fooafter the function is executed, its execution context is popped from the top of the stack, but because the returned setNameand getNamemethods use the variables myNameand inside the foo function test1, these two variables are still stored in memory. This is very much like an exclusive backpack carried by setNamethe and method. No matter where the and method getNameis called , they will carry the exclusive backpack of this function.setName getNamefoo

The reason why it is a dedicated backpack is that it cannot be accessed anywhere except the setNameand functions, so we can call this backpack the closure of the foo function.getName

Ok, now we can finally give a formal definition of a closure. In JavaScript, according to the rules of lexical scope, internal functions can always access the variables declared in their external functions. When an internal function is returned by calling an external function, even if the external function has been executed, the internal function reference The variables of the external function are still stored in memory, and we call the collection of these variables a closure. For example, if the external function is foo, then the collection of these variables is called the closure of the foo function.

To sum it up in one sentence

Functions that can access variables inside other functions are called  closures .

(We understand that it can be understood in this way, but of course we can talk about this example with the interviewer, which directly rises to a new level of understanding what closure is)

Guess you like

Origin blog.csdn.net/pidanl/article/details/127881611