ES 6 adds the let command to declare variables. Unlike var, variables declared with let are only valid in the block-level scope, so for loop counters are suitable for let commands.

Two pieces of code

Take a look at this example:

Code 1

let i = 0
for(i = 0; i<6; i++){
	setTimeout(() = >{
		console.log(i)
	},0)}// Return six sixes
Copy the code

Look at this example:

Code 2

for(let i = 0; i<6; i++){
	setTimeout(() = >{
		console.log(i)
	},0)}// Print out 0, 1, 2, 3, 4, 5
Copy the code

Why do they print different results?

About the setTimeout ()

The setTimeout() method is used to call a function or execute an expression after a specified number of milliseconds. Returns an ID (number) that can be passed to clearTimeout() to cancel execution.

Because JS is single-threaded, single-threaded means that all tasks need to be queued, and only after the previous task has finished can the next task be executed. When setTimeout(() => {},millisec), the functions are put on the task queue, and only when the JS thread is idle and the millisec thread has reached the specified time.

When setTimeout() is 0, the main thread will not execute its specified callback until the current code (stack) completes.

The principle of

It’s easy to understand why code 1 returns six sixes.

let i = 0
for(i = 0; i<6; i++){
	setTimeout(() = >{
		console.log(i)
	},0)}// Return six sixes
Copy the code

When the current for loop is executed and there is a setTimeout() with a time parameter of 0, setTimeout() will be executed after the current for loop is executed, that is, I will be printed. That is, after executing the for loop, there are six I = 6s waiting to execute console.log(I), so six 6s are printed out.

Code 2 is a little harder to understand, due to let features.

for(let i = 0; i<6; i++){
	setTimeout(() = >{
		console.log(i)
	},0)}// Prints 0, 1, 2, 3, 4, 5
Copy the code

Because the variable I is declared by let and currently I is only valid for this loop, each loop’s I is actually a new variable. Although each cycle I is redeclared, the JS internal engine will remember the value of the previous cycle. When initializing the variable I of the previous cycle, it ensures that the next cycle can be calculated on the basis of the previous cycle. In fact, the I of each cycle is a new variable.

SetTimeout () is executed after waiting for the end of the for loop, and prints 0, 1, 2, 3, 4, 5.

Are there any other ways to implement code 2?

Execute function immediately

I saw a way to do this on the web. Before ES6 came out, it was possible to do this using closures.

But before we do that, let’s look at a little bit of code.

for(var i = 0; i < 6; i++){
	setTimeout(function(){
		console.log(i);
	},0);
}// Print out six sixes
Copy the code

When variable I is declared with the var command, it is actually valid globally, so there is only one variable I globally, and similarly to code 1, it prints six sixes.

When we use let, we ask why we print 0, 1, 2, 3, 4, 5 (JS “optimizes” let to make it easier to use). Now, when we go back to the days before ES6, how do we print 0, 1, 2, 3, 4, 5?

That’s using the closure method.

for( var i = 0; i<6; i++) { !function(i){
        setTimeout(function () {
            console.log(i);
        },0)
    }(i);
}// Prints 0, 1, 2, 3, 4, 5
Copy the code

This is possible because setTimeout() in a closure is not exposed globally, but in a separate scope of the closure.

Add an operator to an anonymous function! , ~, (), +, and – are called immediately executing functions. In the era of ES 5, in order to obtain local variables, a function had to be introduced. But if this function has a name, it’s not worth it. The function must then be anonymous, declare the anonymous function, and immediately execute it with a (). But the JS standard considers this syntax illegal.

Let’s add a new variable j

for(i = 0; i < 6; i++ ){
    let j = i
    setTimeout(() = > {
        console.log(i)
    },1000)}// Prints 0, 1, 2, 3, 4, 5
Copy the code

Enter the loop, j1= I =0, end the loop

= >

Enter the loop, j2= I =1, end the loop

= >

Enter the loop, j3= I =2, end the loop

= >

Enter the loop, j4= I =3, end the loop

= >

Enter the loop, j5= I =4, end the loop

= >

Enter the loop, j6= I =5, end the loop

tips

ES6 provides lets, which are easier to use than closures, but at the same time make it easier for us to ignore a lot of details. However, the solution is to solve the problem. We should not forget the essence of the problem, but we should also learn to use tools to improve our efficiency, both of which are to improve ourselves.