JavaScript: Understanding let scope inside for loop [duplicate]

我只是一个虾纸丫 提交于 2021-02-08 09:52:40

问题


Please consider snippet below-

for(let i = 1; i <= 5; i++) {
   setTimeout(function(){
       console.log(i);
   },100);
}

In this case, logs inside setTimeout will contain values of variable i as per each iteration of the for loop, i.e the logs will be as follow

1
2
3
4
5

For this, I have read explanations over the Internet like - let creates a variable declaration for each loop which is block level declaration. So basically it creates a scope within { }.

But I am bit confused regarding this statement. If let creates a variable declaration for each loop, won’t it will be always initialized to 1 as per the loop initialization statement let i=1? Also, variable i is declared, initialized and incremented outside the loop block i.e. curly braces in the for loop statement. So, in each iteration isn’t the same variable i is incremented and utilized? How exactly does let creates a variable declaration for each loop and has value of previous iteration?


回答1:


General Explanation

When you use let in the for loop construct like you show, there is a new variable i created for each invocation of the loop that is scoped just to the block of the loop (not accessible outside the loop).

The first iteration of the loop gets its value from the for loop initializer (i = 1 in your example). The other new i variables that are created each loop iteration get their value from the i for the previous invocation of the loop, not from the i = 1 which is why they aren't all initialized to 1.

So, each time through the loop there is a new variable i that is separate from all the other ones and each new one is initialized with the value of the previous one and then processed by the i++ in the for loop declaration.

For your ES6 code of this:

for(let i = 1; i <= 5; i++) {
   setTimeout(function(){
       console.log(i);
   },100);
} 

In ES5, this would be an essentially equivalent structure. If you really study this, it can be very informative for what's actually happening in your above ES6 code:

(function() {
    for (var i = 1; i <= 5; i++) {
        i = (function(j) {
            setTimeout(function(){
                console.log(j);
            },100);
            return j;
        })(i);
    }
})();

It takes two IIFE (immediately invoked function expressions) to simulate this. The outer one isolates the var i so that it doesn't leak out of the for loop and the inner one provides a separate scope and separate variable for each invocation of the for loop. The return j and the i = (function(j) {...})(i) is to show how the next iteration of the loop is affected by a modification to the loop variable.

Hopefully, this illustrates how incredibly useful let is for for loop in ES6 and how much other code it replaces when you need/want this functionality.

Now for Your Specific Questions

For this, I have read explanations over the Internet like - let creates a variable declaration for each loop which is block level declaration. So basically it creates a scope within { }

let defines variables that have block scope (not function scope like var). And, the { and } that delineate the for loop do indeed define a scope.

Also, variable i is declared, initialized and incremented outside the loop block i.e. curly braces in the for loop statement.

Well, not quite. The for loop is an instruction for how to initialize the first i created for the first invocation of the loop. The fact that the let i = 1 appears outside the loop does look a bit confusing, but it's really just an instruction for what to when it creates the first i variable for the first invocation of the loop. That first i variable doesn't actually exist outside the loop scope.

So, in each iteration isn’t the same variable i is incremented and utilized?

No. When ES6 encounters a for loop with a let definition, it creates a new variable for each iteration of the loop.

How exactly does let creates a variable declaration for each loop and has value of previous iteration?

It isn't let doing this. It's the for loop logic in the ES6+ JS interpreter. This is a special behavior for a for loop that has an index initializer declared with let. So, it's a combination behavior of let and for, but the real logic is in the way the for loop is executed by the interpreter.

Special Case When Modifying the Loop Variable

There is also a special case for let in for loops. If you assign to the value of i in the loop, it will change that particular value of i and it will also affect the next iteration's value of i. This is a bit of a special case, but it allows you to still manipulate the value of i in the loop.

for(let i = 1; i <= 5; i++) {
   let j = i;
   setTimeout(function(){
       console.log(j);
   },100);
   if (i === 2) {
      i++;         // bump the loop increment to skip the 3 value
   }
}

This creates the output:

1
2
4
5

So, this skips the 3 iteration of the loop because when i === 2, we increment it to 3, then the for loop does its i++ iteration and bumps it up to 4, effectively skipping the 3 iteration.




回答2:


A for loop like this:

for (let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 100);
}

Is the same as doing this:

{
  let i = 1;
  setTimeout(function() {
    console.log(i);
  }, 100);
} 

{
  let i = 2;
  setTimeout(function() {
    console.log(i);
  }, 100);
} 

{
  let i = 3;
  setTimeout(function() {
    console.log(i);
  }, 100);
} 

{
  let i = 4;
  setTimeout(function() {
    console.log(i);
  }, 100);
} 

{
  let i = 5;
  setTimeout(function() {
    console.log(i);
  }, 100);
}

The variable is declared and assigned inside the scope of the for loop five separate times, and each instance is completely separate from the others.




回答3:


In javascript you can define a variable through either var or let. The variables which are defined as let does not refined.Lets consider an example code snippet

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript let</h2>

<p id="demo"></p>

<script>
var i = 3;
for (var i = 0; i < 10; i++) {
  // some statements
  document.getElementById("demo").innerHTML += i;
}
document.getElementById("demo").innerHTML += i;
</script>

</body>
</html>

In this code the output will be --> 012345678910 In contrast, the variable with let in the loop does not redeclare the variable outside the loop.

<!DOCTYPE html>
<html>
<body>

   <h2>JavaScript let</h2>

    <p id="demo"></p>

    <script>
let i = 5;
for (let i = 0; i < 10; i++) {
  // some statements
  document.getElementById("demo").innerHTML += i;
}
document.getElementById("demo").innerHTML += i;
</script>

</body>
</html>

Output of above code will be --> 01234567895 Here the variable outside the loop remains unchanged and the inner loop executed and after the loop finished, global variable remains with the same value 5. It basically separates the variable according to their scope.



来源:https://stackoverflow.com/questions/59170277/javascript-understanding-let-scope-inside-for-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!