What is a closure?

Let’s put it this way: a combination of a function bundled with references to its surrounding state (lexical environment) is a closure.

How does each recognize the word combination together to see not to understand 🤣?

Before you get confused, consider the output of the following code:

function sayHello() {
    var sentence = "Hello,world!"; 
    function say() {
        console.log(sentence);
    }
    say();
}
sayHello();
Copy the code

Obviously, the output of the code is: Hello,world! . You can sort out the process:

  1. performsayHellomethods(sayHello ();
  2. Define variablesvar sentence = "Hello,world!" And,sentenceThe scope of a variable is limited tosayHelloThe sayHello method is not externally accessible.Var sentence = “Hello,world!” 😉
  3. callsayHelloInternal methodssayMethods.(say);
  4. becausesayMethod is defined assayHelloInternal, so it can undoubtedly be accessed to the same definition insayHelloVariables in methodssentence. There seems to be nothing wrong with the code.

But this?

function sayHello() {
    var sentence = "Hello,world!"; 
    function say() {
        console.log(sentence);
    }
    return say;
}
var fun = sayHello();
fun();
Copy the code

We might think of the process as:

  1. callsayHelloMethods and methodsfunThe variable holds its return value.Var fun = sayHello();
  2. sayHelloIs a function object:say(return say;). So we can call it externallysayMethods.(fun ();)
  3. Enter thesaySetsentence (); setsentence ()(the console log (sentence);Where is sentencevar sentence = "Hello,world!" ;This. But sayHello is done,sentenceHow can a variable still exist?

Therefore, sentence is undefined? Instead, the output is still: Hello,world! .

How could this be! In this case, we can only assume that the sayHello method instance say is not simply a function, and that it must somehow hold the sentence variable so that it can be accessed when executed.

Originally, functions in JavaScript form closures. Closures are a combination of functions and the lexical environment in which they are declared. The environment contains any local variables that were in scope when the closure was created.

As we expected! :

Say is the internal sayHello method. When we get an instance of the say method (var fun = sayHello()), the say instance ensures that all of its internal variables are properly accessed. Therefore, it is not surprising that when we call fun, an instance of say, we can access the variable sentence used by say.

Bad and good…

Closures look strange, as you might expect if every time a function instance is created, its internal methods have to be redefined.

Take the constructor as an example:

function Person(name,age) {
    this.name = name;
    this.sayHello = function(){console.log("My name is ",name)};
}
Copy the code

According to closures, sayHello is defined repeatedly each time a Person is instantiated. If there are a lot of instance objects, repeating methods can take up a lot of space. Fortunately, prototypes can be used here:

function Person(name) {
    this.name = name;
}

Person.prototype.sayHello = function(){console.log("My name is ".this.name)};
Copy the code

So what’s good about closures? Of course, closures have their advantages.

Closures bind external variables and method instances together. Is this an encapsulation?

We can:

var names = ["chao"."zhao"."tao"."yao"];
var say = function(str){
    return function(){
        console.log("My name is ",str);
    };
};

var funs =[];
for(var i in names)
    funs[i] = say(names[i]);

for(var f of funs)
    f();
Copy the code

The internal method of SAY maintains its own lexical environment, holding the variable STR. So, although STR is constantly changing (each STR is a new STR), the method instances are maintained one by one, so the output of each method instance in the array funs is ultimately called is different:

My name is  chao
My name is  zhao
My name is  tao
My name is  yao
Copy the code

👌, probably so, each big guy reward a praise 👍 bie!

— — — — — —

One last example if you don’t use an inner function:

var names = ["chao"."zhao"."tao"."yao"];
var say = function(str){
    console.log("My name is ",str);
};

var funs =[];
for(var i in names)
    funs[i] = function(){console.log("My name is "+names[i])};

for(var f of funs)
    f();
Copy the code

Output:

My name is  yao
My name is  yao
My name is  yao
My name is  yao
Copy the code

This is because functions maintain the lexical context of each closure, but I remains the same. Keep going, keep going, always the I that ends up equal to 3 (if I use for(var I = 0; i < names.Length; I ++) and finally I is 4). Let I instead of var I is different, the reason can be explained by 😆.