Erwin Moller wrote:
> […] Also, we can keep the scope around the loop cleaner by moving the code
> that creates the new elements into the scope of each loop.
Not only the loop, but also the *Block* statement associated with the loop
statement. See below.
> […]
> Compare it to the following code:
>
> var list = document.getElementById("list");
> let i = 1;
> while (i <= 5) {
> let item = document.createElement("li");
> item.appendChild(document.createTextNode("Item " + i));
>
> item.onclick = function (ev) {
> console.log("Item " + i + " is clicked.");
> };
> list.appendChild(item);
> i++;
> }
>
> In the above code 'let' behaves as 'var' and all clicks will result in
> "Item 6 is clicked".
>
> (I am not sure I should use 'closure' in this context, but the code
> behaves that way.)
“Closure” is the correct term here.
<
https://en.wikipedia.org/wiki/Closure_(computer_programming)>
> So what happens differently between these two codepieces?
> 1) let i = 1;
> while (i <= 5) {...
>
>
> and
>
> 2) for (let i = 1; i <= 5; i++) {...
>
>
> Is the use of 'let' in the for-loop considered INSIDE the block?
“var” does variable scoping based on the VariableEnvironment of execution
contexts. “let” enforces *lexical* *block* scoping or, IOW, scoping “to the
running execution context’s LexicalEnvironment” (ECMAScript Language
Specification [ES] 6.0 and 7.0, § 13.3.1).
Different to a declaration with “var”, a variable declared with “let” is
only defined in the same block and inner blocks (like e.g. Python¹). If you
declare a variable with “let” outside of a block, then it works like “var”
inside the block because it is bound to the outer block’s lexical
environment.
_______
¹ Different to “var” and to Python, there can only be one “let” declaration
for the same variable in the same block/LexicalEnvironment. Otherwise it
is a syntax error (“SyntaxError: Identifier 'foo' has already been
declared”). Note that this is purely syntax-related: You can have
one declaration with “let” for the same variable inside a loop, but not
more. [AFAIK, Python does not have a variable declaration without
explicit initialization, so there is no obvious difference between a
declaration with initialization and a simple assignment. PHP and a
number of other scripting languages exhibit the same issue.]
> (Because literally, it is not).
The difference between the “while” statement and the “for” statement
(variants that do not contain the “in” or “of” keyword) is that the latter
has an initialization part that allows for variable declarations.
Therefore, there is a special “for” statement where with a *lexical*
declaration the variable can be bound to the “for” statement instead of the
adjacent block, and still, since *semantically* the adjacent block has to
have access to the variables declared in the “for” statement, it works as if
the “for” statement would create a block of its own (ES 6.0 and 7.0,
§ 13.7.4).
A most interesting thing happens when you use “for (let …)” and move the
post-increment operation into the block: you end up with the console saying
“Item 2 is clicked” when you clicked “Item 1” and so on. Intuitively you
would think that an increment in the “for” statement or in the adjacent
block were equivalent; but that is not so if the variable was declared with
“let” in the “for” statement.
If you find “let” confusing, I suggest that you do not use it. That would
have the additional advantage of writing backwards-compatible code.
--
PointedEars
FAQ: <
http://PointedEars.de/faq> | SVN: <
http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | ES Matrix: <
http://PointedEars.de/es-matrix>
Please do not cc me. / Bitte keine Kopien per E-Mail.