I have been vague about the concept of closures before, and there is a long discussion on the Internet. Now I have summarized some knowledge points about closures through my own understanding and learning, and I can point out the wrong places. We can learn from each other.

Let’s start with the scope of some variables:

There are two types of scope for variables: global variables and local variables.

Global variables:

var n = 999;// Global variables
function f1(){
  console.log(n);
}
f1();/ / 999
Copy the code

Local variables:

function f1(){
  var n = 999;// Local variables
}
console.log(n);//n is not defined
Copy the code

A simple understanding of closures

Let’s take a look at MDN’s definition of closures:

A combination of a function bound to (or surrounded by) references to its surrounding state (lexical environment) is a closure. That is, closures allow you to access the scope of an outer function within an inner function. In JavaScript, whenever a function is created, the closure is created at the same time the function is created.

An important one: closures allow you to access the scope of an outer function in an inner function.

It doesn’t matter if you don’t understand now, read on:

The best way to learn a concept is to go to a demo to understand it and analyze it. Here is a piece of code. This is the simplest closure:

function f1(){
  var n = 999;
  
  function f2(){
    console.log(n);
  }
  
  return f2F2 = f2; // Return the inner function f2, so that f2 can be read in f1.
  
}

var result = f1();
result();/ / 999
Copy the code
  • Let’s first define a normal function f1;
  • Define a normal function f2 in f1, and the internal variable n in f1;
  • Returns the function f2 in f1 (rather, a reference to F2 is returned in F1);
  • Assign the return value of f1 to the variable result;
  • Perform the result

In the above code, the f1 function has a nested function f2, and F2 calls the f1 variable, so the combination of the variable n and the function F2 is a closure.

So why closures? Closures allow you to access the scope of an outer function in an inner function. For analysis, let’s look at another graph:

F1 is an external function, the variable n is a local variable of the external function, and f2 is an internal function nested in F1. The internal function F2 calls the variable n of the external function F1, so f2 and the variable n form a closure.

Then, we can derive the conditions for generating closures:

  • An inner function is nested inside an outer function; For example, an inner function f2 is nested inside the outer function F1
  • A nested inner function calls an inner variable or function of an outer function; For example, the f2 inner function calls the variable n of the external function F1

As long as these two conditions are met, a closure is generated.

So why return F1, you might ask?

If you do not return F2, you will not be able to use the closure F2. If you do not return F2, you will be able to use f2 variables and data in F1.

So what exactly is a closure?

A closure is a function that has access to the internal variables or data in the scope of another function. In JS, as long as the internal function can read the variables or data of the external function, the vice versa, the closure can be simply understood as a function defined inside a function.

Conclusion:

A closure is a function that has access to variables inside another function.

Closures occur when an inner function has a reference to a local variable of an outer function.

Here I believe you have a simple understanding of closures, but only understanding is not enough, we learn to learn the same technology, the most important thing is to learn to use, then we continue to understand it.

The classic use scenario for closures

1, return an internal function, read the internal function variable;

One of the biggest uses mentioned earlier is to read variables from internal functions;

function f1(){
  var n = 999;
  function f2(){
    console.log(n);
  }
  returnF2; }var result = f1();
result();/ / 999
Copy the code

2. Functions as arguments

var n = 999;

function f1(){
  var n = 1000;
  function f2(){
    console.log(n);
  }
  return f2
}

function f3(p){
  var n = 1001;
  p();
}

f3(f1());/ / 1000
Copy the code

3, IIFE (self-executing function)

var n = 999;
(function f1(){
  console.log(n); }) ()/ / 999
Copy the code

F1 () is a closure that calls the global variable n (that is, the variable n under window);

4. Loop assignment

for(var i = 0; i<10; i++){
  (function(j){
    setTimeout(function(){
      console.log(j);
    },1000)
  })(i)
}
//1,2,3,4,5,6,7,8,9,10 print in sequence
Copy the code

Using a callback is using a closure

window.n = 999;
setTimeout(function f1(){
  console.log(window.n);
},1000)
Copy the code

6. Keep variable values created by external functions in memory at all times;

Take a look at the following code:

function f1(){
  var n = 999;
  function f2(){
    console.log(n++);
  }
  result f2
}
var result = f1();
result();/ / 1000
Copy the code

The internal variable n of f1 in the above code is always in memory and will not be cleared automatically after the f1 call ends. Look at another piece of code:

function f1(){
  var n = 999;
  nAdd = function(){
    n+=1;
  }
  function f2(){
    console.log(n);
  }
  result f2
}

var result = f1();
result();/ / 999
nAdd();
result();/ / 1000
Copy the code

The return value of function F1 is assigned to the global variable result. The return value of function F1 is actually f2, which is assigned to the global variable result. As a result, F2 is always in memory, and the existence of F2 depends on f1. It is collected by the garbage collection mechanism (GC mechanism), so it is easy to cause memory leaks.

A memory leak is a variable that you can’t access or use and that occupies memory and can’t be reused.

7. Encapsulate private objects and private methods of objects;

var Counter = (function(){
   var privateCounter = 0;
   return function changeBy(val){
     privateCounter += val;
   }
   return {
     increment:function(){
       changeBy(1);
     },
     decrement:function(){
       changeBy(-1);
     },
     value:function(){
       returnprivateCounter; }}}) ();console.log(Counter.value());/ / 0
Counter.increment();
Counter.increment();
console.log(Counter.value());/ / 2
Counter.decrement();
console.log(Counter.value());/ / 1
Copy the code

What should I pay attention to when using closures?

Because using closures will contain the scope of other functions, occupying more memory space than other functions, and will not be collected by the garbage collection mechanism (GC) after the call, excessive use of closures will overuse memory and cause memory leaks.

4. Closure questions

1. What is a closure and what does it do? Write a simple closure example.

2. Do closures cause memory leaks?

Yes, because using closures will contain the scope of other functions, occupying more memory space than other functions, and will not be collected by the garbage collection mechanism after the call ends. Excessive use of closures will overuse memory and cause memory leaks.

3. For loops and closures

var data = [];

for(var i = 0; i < 3; i++){
  data[i] = function (){
  console.log(i);
  };
}

data[0] ();/ / 3
data[1] ();/ / 3
data[2] ();/ / 3
Copy the code

The variable I in the above code belongs to a global variable with a common scope and all outputs are three 3’s. Use closures to improve the above notation to achieve the desired effect:

var data = [];
for(var i = 0; i < 3; i++){
  (function(j){
    setTimeout(data[j] = function(){
    console.log(j);
    },0)
  })(i)
}
data[0] (); data[1] (); data[2] ();Copy the code

4. Write the output of the following code:

Question 1 4-1:

var n = 10;
function f1(){
  var n = 20;
  function f2(){
    n++
    console.log(n);
  }
  f2();
  return f2
}

var result = f1();/ / 21
result();/ / 22
result();/ / 23
console.log(n);/ / 10
Copy the code

Question 2 4-2:

function makeAdder(x){
  return function(y){
    returnx+y; }}var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2));/ / 7
console.log(add10(2));/ / 12
Copy the code

Question 3 4-3:

var Counter = (function(){
   var privateCounter = 0;
   return function changeBy(val){
     privateCounter += val;
   }
   return {
     increment:function(){
       changeBy(1);
     },
     decrement:function(){
       changeBy(-1);
     },
     value:function(){
       returnprivateCounter; }}}) ();console.log(Counter.value());/ / 0
Counter.increment();
Counter.increment();
console.log(Counter.value());/ / 2
Counter.decrement();
console.log(Counter.value());/ / 1
Copy the code

Question 4 4-4:

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      returnprivateCounter; }}};var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); / / 0
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); / / 2
Counter1.decrement();
console.log(Counter1.value()); / / 1
console.log(Counter2.value()); / / 0
Copy the code

Counter1 and Counter2 are two separate closures, and a change in the value of a variable in one closure does not affect a variable in the other.

Question 5 4-5:

for(var i = 0; i < 10; i++){
  setTimeout(
    function(){
    console.log(i);
    },1000)}//10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 every 1 second, a total of 10
Copy the code

Because setTimeout is asynchronous and the for loop is synchronous, the asynchronous code starts executing after the synchronous code is finished and I is already 10, so the last print of I is 10.

If var is replaced by let, the output is also different:

for(let i = 0; i < 10; i++){
  setTimeout(
    function(){
    console.log(i);
    },1000)}/ / 1,2,3,4,5,6,7,8,9,10
Copy the code

If we use var in the for loop, then I is a global variable and the value of I is 10 at the end of the loop.

Continue to supplement the update, the record is not good at the point of revision, common progress ~

Every day to cheer themselves up, today also want to refueling duck ~