问题
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