This is the 8th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

I. Definition of closures

MDN defines closures as:

Closures are functions that have access to free variables.

So what is a free variable?

A free variable is a variable that is used in a function but is neither a function parameter nor a local variable of the function.

From this, we can see that a closure consists of two parts:

Closure = function + free variables that the function can access

To put it simply:

Closures are functions that can read variables inside other functions

In function A there is function B, which calls A variable in function A, so function B is called the closure of function A.

function foo() {
  let a = 2;
  function bar() {
    console.log(a);
  }
  bar();
}
foo(); / / 2
Copy the code

Two, loops and closures

for (var i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log("i: ", i);
  }, 1000);
}
console.log(i);

/ / output
/ / 5;
// i: 5;
// i: 5;
// i: 5;
// i: 5;
// i: 5;
Copy the code

To understand the above code, first we need to understand the concept:

  • JS is divided into synchronous tasks and asynchronous tasks
  • Synchronization tasks are executed on the main thread, forming an execution stack
  • Outside of the main thread, the event-triggering thread manages a task queue and places an event in the task queue whenever the asynchronous task has run results.
  • Once all the synchronous tasks in the execution stack are finished (at this time the JS engine is idle), the system will read the task queue, add the running asynchronous tasks to the execution stack, and start to execute.

The above code uses the timer, when the JS engine thread executes to this section of code, then put the timer to the timer thread to time, at this time THE JS engine thread executes the task inside the synchronization stack. When the timer completes, the callback function is pushed to the message queue. After the code in the stack is finished executing, it reads the events in the message queue.

Because of JS’s function scope, callback functions are pushed to the message queue without arguments. At the end of the for loop, since I is defined with var, so var is a global variable (there is no function here, if there is a variable inside the function), I is 5.

How to solve it?

// Let is block-level scope, and the current block is the body of the loop
for (let i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log('i: ',i);
  }, 1000);
}
console.log(i);

/ / output
/ / 5
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
Copy the code
// This is the function-level scope, using closures to simulate block-level scope
for (var i = 0; i < 5; i++) {
  (function(){
    var j = i;
    setTimeout(function() {
      console.log('i: ',j);
    }, 1000); }) (); }console.log(i);

/ / output
/ / 5
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
Copy the code
// Or pass a parameter and use a closure
for (var i = 0; i < 5; i++) {
  (function(j){
    setTimeout(function() {
      console.log('i: ',j);
    }, 1000);
  })(i);
}
console.log(i);

/ / output
// i is not defined
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
Copy the code
// The third argument to setTimeout
for (var i = 0; i < 5; i++) {
  setTimeout(function timer(j) {
    console.log('i: ', j);
  }, 1000, i);
}
console.log(i);

/ / output
// i is not defined
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
Copy the code