Javascript closure from shallow to deep topic

Closures are functions that can read variables inside other functions

The two biggest
uses are the aforementioned variables that can be read inside the function;
the other is to keep the values ​​of these variables in memory.

1. Variable scope
To understand closures, we must first understand the special variable scope of JavaScript.
There are two types of variable scopes: global variables and local variables.
The peculiarity of the javascript language is that the global variables can be directly read inside the function, but the local variables inside the function cannot be read outside the function.
Note: When declaring variables inside a function, be sure to use the var command. If you don't use it, you are actually declaring a global variable!

2. How to read local variables inside a function from outside?
For various reasons, we sometimes need to access local variables inside functions. However, as mentioned above, under normal circumstances, this cannot be done! This can only be achieved through workarounds.
That is, inside the function, define another function.

 <script> 
function f1(){
    var n=999;
    return function f2(){
      return n;
    }
  }
window.console.log(f1()())//999

</script> 

In the above code, the function f2 is included inside the function f1, and all local variables inside f1 are visible to f2. But not vice versa, the local variables inside f2 are invisible to f1.
This is the unique " chain scope " structure of the Javascript language, and the
child object will look up all the variables of the parent object level by level. Therefore, all variables of the parent object are visible to the child object, but not vice versa.
Since f2 can read the local variables in f1, as long as f2 is used as the return value, can't we read its internal variables outside f1!

Consider again the output of the following two examples:

Currently this is in the global scope:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
window.console.log(window.object.getNameFunc()());//The Window

Currently this is in the local scope:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  window.console.log(window.object.getNameFunc()()); //My Object

The window object is deliberately written in the code so that new students can understand the process of the entire scope more clearly. I hope God will not complain.

The basics have been understood, so let's come to a difficult topic:

function fun(n,o){
    console.log(o);
    return {
        fun:function(m){//[2]
            return fun(m,n);//[1]
        }
    }
}
var a=fun(0);
a.fun(1);
a.fun(2);
a.fun(3);
var b=fun(0).fun(1).fun(2).fun(3);
var c=fun(0).fun(1);
c.fun(2);
c.fun(3);

The answer is as follows:
write picture description here

The fun attribute of the object returned by the equivalent code
return corresponds to a newly created function object. This function object will form a closure scope so that it can access the variable n of the outer function and the outer function fun. The function is confused with the fun attribute. We modify the above code as follows:
Code B

function _fun_(n,o){
    console.log(o);
    return {
        fun:function(m){
            return _fun_(m,n);
        }
    }
}

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0

var b=_fun_(0).fun(1).fun(2).fun(3);
//undefined,0,1,2

var c=_fun_(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1

Then some students asked, why can you change it like this? How can you be sure that the fun at [1] is not the fun where the code [2] is located. You must know that the fun attribute here points to a function object~
Here it is When it comes to the lexical scope of JS, the scope of JS variables exists in the function body, that is, the function body, and the scope of the variable is determined when the function is defined and declared, not when the function is running.
The following code

var name="global";
function foo(){
    console.log(name);
}
function fooOuter1(){
    var name="local";
    foo();
}
fooOuter1();//输出global 而不是local,并且和闭包没有任何关系
function fooOuter2(){
    var name="local";
    function foo(){
        console.log(name);
    }
    foo();
}
fooOuter2();//输出local 而不是global,在函数声明是name变量作用域就在其外层函数中,嗯嗯就是闭包~

Ok, let's go back to the topic, in the function declaration definition stage, the anonymous function at [2] is defined and declared, and it is found that a function object named fun needs to be referenced at [1], then first search in the current function body and find that there is no , then go to its outer function - the wrapper function of this anonymous function to find it, and find nothing. Go to the outer function and find that there is no function package outside, then go to the global environment to find it, and finally found it. ...specify the fun function as the fun function object in the global environment and add it to the closure of the anonymous function. So far we know why code B is equivalent to code A~~~

Create a closure scope
After lexical analysis, JS determines a closure, which is the closure of the anonymous function corresponding to the returned object fun attribute - the function internal variable n of accessing func and its outer function in the global environment;
Each time func is executed, the scope information of the variables in the closure will be passed to the function execution environment for use in obtaining the variable values ​​during function execution.

execute output

var a=_fun_(0);//undefined
a.fun(1);//0
a.fun(2);//0
a.fun(3);//0

The fun function executes, because the second parameter is undefined, and the output is undefined. Then return an object with the fun attribute, pointing to a function object - with a closure, able to access the fun and variable n_
a.fun(1) execute the fun method of the returned object, pass in the value of m 1, the call returns fun (1,0)
so the output is 0, a.fun(2), a.fun(3) and a.fun(1)
debug screenshots under breakpoints:
write picture description here
write picture description here
write picture description here
write picture description here

var b=_fun_(0).fun(1).fun(2).fun(3);

Equivalent code

var b=_fun_(0);
var b1=b.fun(1);
var b2=b1.fun(2);//[3]
var b3=b2.fun(3);//[4]

The first two sentences are the same as the above output undefined, 0. When [3] is called, there is a closure in the b1 object, which refers to the fun function and the outer function variable n=1, so the function call executed by the anonymous function is fun (2,1), the output result is 1, and a new object is returned.
When [4] is executed, the b2 object also has a closure, which references the fun function and the outer function variable n=2, executes fun (3,2), and the output result is 2

var c=fun(0).fun(1);//undefined,0,
c.fun(2);//1
c.fun(3); //1

If you can understand the previous code execution explanation, and understand the above code execution output, there will be no problem

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325648426&siteId=291194637