admin管理员组文章数量:1336143
My JavaScript book, "JavaScript The Definitive Guide, 6th Ed.", page 270 includes this text and code:
"... in a for loop, the initializer expression is evaluated outside the scope of the new variable"
let x = 1;
for (let x = x + 1; x < 5; x++) {
console.log(x); // prints 2, 3, 4
}
When I run the above code (in the latest version of Chrome and FF) however, I get console errors:
ReferenceError: x is not defined
can't access lexical declaration `x' before initialization
Is the code in the book incorrect? (There's nothing on the book's errata site re: this.)
My JavaScript book, "JavaScript The Definitive Guide, 6th Ed.", page 270 includes this text and code:
"... in a for loop, the initializer expression is evaluated outside the scope of the new variable"
let x = 1;
for (let x = x + 1; x < 5; x++) {
console.log(x); // prints 2, 3, 4
}
When I run the above code (in the latest version of Chrome and FF) however, I get console errors:
ReferenceError: x is not defined
can't access lexical declaration `x' before initialization
Is the code in the book incorrect? (There's nothing on the book's errata site re: this.)
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Feb 12, 2019 at 15:26 Gerald LeRoyGerald LeRoy 1,2772 gold badges11 silver badges18 bronze badges 5-
3
x
is being redeclared, that's the issue. – briosheje Commented Feb 12, 2019 at 15:27 - 2 @briosheje no, it doesn't get redeclared. It gets shadowed. – Jonas Wilms Commented Feb 12, 2019 at 15:56
-
@JonasWilms true, indeed. Though the issue is still there. It's shadowed by the local
x
variable, right? – briosheje Commented Feb 12, 2019 at 15:57 - @briosheje the issue is trying to access a variable inside of its initializer. The quoted paragraph is just wrong. – Jonas Wilms Commented Feb 12, 2019 at 16:07
- Thanks everyone! This is making more sense to me now. I now have a MUCH better understanding of how the keyword let behaves! – Gerald LeRoy Commented Feb 12, 2019 at 20:08
5 Answers
Reset to default 5The problem is not really that x
gets declared twice. It is just that you are trying to access the inner x
before it got initialized:
let x = x /* doesn't exist yet*/;
Wether there is another x
in the outer scope (initializers in a for
loop are inside their own scope) doesn't matter, the x
will refer to the variable in the current scope, as it already got declared (due to hoisting), but wasn't initialized yet:
let x = 0; // irrelevant
{ // x gets declared as part of this scope
x; // thats an error too as x is not initialized yet
let x = 1; // initialization
x; // now it can be accessed
}
The part between the beginning of a scope and a let
declaration is called the "temporal dead zone" ...
"... in a for loop, the initializer expression is evaluated outside the scope of the new variable"
No, otherwise you couldn't refer to other variables in the initializer:
for(let a = 1, b = a; ; )
As always, the definite answer can be found in the spec:
13.7.4.7 Runtime Semantics: LabelledEvaluation
IterationStatement : for ( LexicalDeclaration Expression ; Expression ) Statement
Let oldEnv be the running execution context's LexicalEnvironment.
Let loopEnv be NewDeclarativeEnvironment(oldEnv).
[...]
Let boundNames be the BoundNames of LexicalDeclaration.
For each element dn of boundNames [..]
Perform ! loopEnvRec.CreateImmutableBinding(dn, true).
Set the running execution context's LexicalEnvironment to loopEnv.
Let forDcl be the result of evaluating LexicalDeclaration.
[...]
As you can see, the running execution context is loopEnv
while the LexicalDeclaration (the initializers) gets evaluated, not oldEnv
.
TLDR: Not only the example is wrong, but also the paragraph.
The only issue is that x
is being redeclared shadowed (as mentioned by Jonas above), hence it throws an error.
Just remove the second let
and everything will work as expected.
let x = 1;
for (x = x + 1; x < 5; x++) {
//^---- note the missing "let" here.
console.log(x); // prints 2, 3, 4
}
If you copied that from a book, then that's a book issue.
https://jsfiddle/hto9udmj/
Further infos about variable declarations can be found here: https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Statements/let
Further infos about variables shadowing: An example of variable shadowing in javascript
Is the code in the book incorrect? (There's nothing on the book's errata site re: this.)
I believe the books was correct; when let
was introduced for the first time years ago in Firefox.
Specifically, it didn't have the temporal dead zone, and it behaves internally more like var
, just block scoped.
In Firefox 44, there was a breaking change that makes let
and const
following the standards:
https://blog.mozilla/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/
Including the introduction of the temporal dead zone.
So, yes, the book now is incorrect; since you're trying to do something like:
let x = 0;
{
let y = x; // `let` is block-scope,
// so this `x` is actually the `x`
// defined below, not the one outside
// the scope, hence the `ReferenceError`.
let x = 1;
}
You are initializing x twice and thus getting error. Rename one x to i
let x = 1;
for (let i = x + 1; i < 5; i++) {
console.log(i); // prints 2, 3, 4
}
The problem is that you redeclare x
within the for
loop and since let
only exists within the given context, after the loop is done x
doesn't exist anymore.
Either declare x
once outside of the for
loop, or use var
. var
adds the variable to a global scope, so it'll exist after the for
loop is done.
let x = 1;
for (x = x + 1; x < 5; x++) {}
console.log(x);
With var:
for (var x = 2; x < 5; x++) {}
console.log(x);
本文标签: JavaScript for loop with letStack Overflow
版权声明:本文标题:JavaScript for loop with let - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742395869a2466907.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论