Explanation of `let` and block scoping with for loops
Is this just syntactic sugar for ES6?
No, it's more than syntactic sugar. The gory details are buried in §13.6.3.9CreatePerIterationEnvironment
.
How is this working?
If you use that let
keyword in the for
statement, it will check what names it does bind and then
- create a new lexical environment with those names for a) the initialiser expression b) each iteration (previosly to evaluating the increment expression)
- copy the values from all variables with those names from one to the next environment
Your loop statement for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
desugars to a simple
// omitting braces when they don't introduce a block
var i;
i = 0;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
…
while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
does "desugar" to the much more complicated
// using braces to explicitly denote block scopes,
// using indentation for control flow
{ let i;
i = 0;
__status = {i};
}
{ let {i} = __status;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
…
JavaScript: Understanding let scope inside for loop
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);
}
Explanation of `let` and block scoping with for loops
Is this just syntactic sugar for ES6?
No, it's more than syntactic sugar. The gory details are buried in §13.6.3.9CreatePerIterationEnvironment
.
How is this working?
If you use that let
keyword in the for
statement, it will check what names it does bind and then
- create a new lexical environment with those names for a) the initialiser expression b) each iteration (previosly to evaluating the increment expression)
- copy the values from all variables with those names from one to the next environment
Your loop statement for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
desugars to a simple
// omitting braces when they don't introduce a block
var i;
i = 0;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
…
while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
does "desugar" to the much more complicated
// using braces to explicitly denote block scopes,
// using indentation for control flow
{ let i;
i = 0;
__status = {i};
}
{ let {i} = __status;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
…
Explanation of `let` and block scoping with for loops
Is this just syntactic sugar for ES6?
No, it's more than syntactic sugar. The gory details are buried in §13.6.3.9CreatePerIterationEnvironment
.
How is this working?
If you use that let
keyword in the for
statement, it will check what names it does bind and then
- create a new lexical environment with those names for a) the initialiser expression b) each iteration (previosly to evaluating the increment expression)
- copy the values from all variables with those names from one to the next environment
Your loop statement for (var i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
desugars to a simple
// omitting braces when they don't introduce a block
var i;
i = 0;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
i++;
…
while for (let i = 0; i < 10; i++) process.nextTick(_ => console.log(i));
does "desugar" to the much more complicated
// using braces to explicitly denote block scopes,
// using indentation for control flow
{ let i;
i = 0;
__status = {i};
}
{ let {i} = __status;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
if (i < 10)
process.nextTick(_ => console.log(i))
__status = {i};
} { let {i} = __status;
i++;
…
Related Topics
How to Get the Difference Between Two Arrays in JavaScript
How to Add a Delay in a JavaScript Loop
How to Remove a Property from a JavaScript Object
JavaScript Post Request Like a Form Submit
How to Obfuscate (Protect) JavaScript
Simplest Code For Array Intersection in JavaScript
How to Set/Unset a Cookie With Jquery
Error: Can't Set Headers After They Are Sent to the Client
Uncaught Referenceerror: $ Is Not Defined
How to Create a File in Memory For User to Download, But Not Through Server
What Is the 'New' Keyword in JavaScript
Ways to Deal With #Document Under Iframe
How to Format Numbers as Currency Strings
How to Remove All Duplicates from an Array of Objects
Generating Random Whole Numbers in JavaScript in a Specific Range