用于循环的JavaScript for let

问题描述 投票:1回答:5

我的JavaScript书籍“JavaScript The Definitive Guide,第6版”,第270页包含以下文本和代码:

“...在for循环中,初始化表达式的计算超出了新变量的范围”

let x = 1;
for (let x = x + 1; x < 5; x++) {
    console.log(x); // prints 2, 3, 4
}

当我运行上面的代码(在最新版本的Chrome和FF中)时,我收到控制台错误:

ReferenceError:未定义x

初始化之前无法访问词法声明`x'

书中的代码是否不正确? (本书的勘误表网站上没有任何内容:这个。)

javascript let
5个回答
4
投票

唯一的问题是x正在 重新声明 阴影(如上面的Jonas所述),因此它会抛出一个错误。

只需删除第二个let,一切都会按预期工作。

let x = 1;
for (x = x + 1; x < 5; x++) {
   //^---- note the missing "let" here. 
   console.log(x); // prints 2, 3, 4
}

如果你从书中复制了那本书,那就是书籍问题。

https://jsfiddle.net/hto9udmj/

关于变量声明的更多信息可以在这里找到:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

关于变量阴影的更多信息:An example of variable shadowing in javascript


3
投票

问题不在于x被宣布两次。只是你在初始化之前尝试访问内部x

 let x = x /* doesn't exist yet*/;

另外在外部范围内有另一个xfor循环中的初始化器在它们自己的范围内)并不重要,x将引用当前范围中的变量,因为它已经声明(由于提升),但是尚未初始化:

 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
 }

范围开头和let声明之间的部分称为“时间死区”......

“...在for循环中,初始化表达式的计算超出了新变量的范围”

不,否则您无法在初始化程序中引用其他变量:

 for(let a = 1, b = a; ; )

一如既往,明确的答案可以在规范中找到:

13.7.4.7运行时语义:LabelledEvaluation

IterationStatement:for(LexicalDeclaration Expression; Expression)Statement

  1. 让oldEnv成为正在运行的执行上下文的LexicalEnvironment。
  2. 设loopEnv为NewDeclarativeEnvironment(oldEnv)。

[...]

  1. 让boundNames成为LexicalDeclaration的BoundNames。
  2. 对于boundNames [..]的每个元素dn 表演! loopEnvRec.CreateImmutableBinding(dn,true)。
  3. 将正在运行的执行上下文的LexicalEnvironment设置为loopEnv。
  4. 让forDcl成为评估LexicalDeclaration的结果。

[...]

如您所见,正在运行的执行上下文是loopEnv,而LexicalDeclaration(初始化程序)被评估,而不是oldEnv

TLDR:这个例子不仅错误,而且还有段落。


2
投票

您正在初始化x两次,从而出错。将一个x重命名为i

let x = 1;
for (let i = x + 1; i < 5; i++) {
    console.log(i); // prints 2, 3, 4
}

2
投票

书中的代码是否不正确? (本书的勘误表网站上没有任何内容:这个。)

我相信这些书是正确的;当let几年前第一次在Firefox中推出时。

具体来说,它没有temporal dead zone,它的内部行为更像var,只是块范围。

在Firefox 44中,有一个突破性的变化使letconst遵循标准:

https://blog.mozilla.org/addons/2015/10/14/breaking-changes-let-const-firefox-nightly-44/

包括引入时间死区。

所以,是的,这本书现在是不正确的;因为你正在尝试做类似的事情:

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;
}

0
投票

问题是你在x循环中重新声明for,因为let只存在于给定的上下文中,循环完成后x不再存在。

要么在x循环之外声明for,要么使用varvar将变量添加到全局范围,因此它将在for循环完成后存在。

let x = 1;
for (x = x + 1; x < 5; x++) {}
console.log(x);

随着var:

for (var x = 2; x < 5; x++) {}
console.log(x);
© www.soinside.com 2019 - 2024. All rights reserved.