Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #31433 > unrolled thread

Confused about let and var

Started byErwin Moller <erwinmollerusenet@xs4all.nl>
First post2016-09-23 10:20 +0200
Last post2016-09-24 18:12 +0200
Articles 3 — 3 participants

Back to article view | Back to comp.lang.javascript


Contents

  Confused about let and var Erwin Moller <erwinmollerusenet@xs4all.nl> - 2016-09-23 10:20 +0200
    Re: Confused about let and var Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-23 19:26 +0100
    Re: Confused about let and var Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2016-09-24 18:12 +0200

#31433 — Confused about let and var

FromErwin Moller <erwinmollerusenet@xs4all.nl>
Date2016-09-23 10:20 +0200
SubjectConfused about let and var
Message-ID<57e4e5d9$0$876$e4fe514c@news.xs4all.nl>
On this page:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

you can find the following example:

=============================================================
var list = document.getElementById("list");

for (let i = 1; i <= 5; i++) {
   let item = document.createElement("li");
   item.appendChild(document.createTextNode("Item " + i));

   item.onclick = function (ev) {
     console.log("Item " + i + " is clicked.");
   };
   list.appendChild(item);
}



The example above works as intended because the five instances of the 
(anonymous) inner function refer to five different instances of the 
variable i. Note that it does not work as intended if you replace let 
with var, since all of the inner functions would then return the same 
final value of i: 6. 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.

=============================================================

This example of  'let' is confusing to me.

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.)

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? 
(Because literally, it is not).

Thanks for your time!

Regards,
Erwin Moller


-- 
"That which can be asserted without evidence, can be dismissed without 
evidence."
-- Christopher Hitchens

[toc] | [next] | [standalone]


#31437

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-09-23 19:26 +0100
Message-ID<87intmh3pr.fsf@bsb.me.uk>
In reply to#31433
Erwin Moller <erwinmollerusenet@xs4all.nl> writes:

> On this page:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
>
> you can find the following example:
>
> =============================================================
> var list = document.getElementById("list");
>
> for (let i = 1; i <= 5; i++) {
>   let item = document.createElement("li");
>   item.appendChild(document.createTextNode("Item " + i));
>
>   item.onclick = function (ev) {
>     console.log("Item " + i + " is clicked.");
>   };
>   list.appendChild(item);
> }
<snip>
> This example of  'let' is confusing to me.
>
> 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.)
>
> 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?

That's one way to look at it, yes.  The actual rules are, as always with
ECMA 262, very fussy indeed, but the 6th edition didn't just introduce
'let' declarations, it it also defined a whole new form of 'for'
statement in which the first part in the ()s is a 'LexicalDeclaration'.
The semantics of the new form make it plain that every loop execution
occurs in a new environment with a fresh binding for the lexical
variables.

> (Because literally, it is not).

Curiously, in C, a for statement constitutes a block which starts at the
for keyword so there is a block even when there is no compound statement
controlled by the for.  ECMAScript does not do that, but the rules have
the same effect.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#31442

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2016-09-24 18:12 +0200
Message-ID<1759466.oMNUckLgyt@PointedEars.de>
In reply to#31433
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.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web