JavaScript for let循环

时间:2019-02-12 15:26:29

标签: javascript let

我的JavaScript书“ JavaScript权威指南,第六版”,第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”

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

5 个答案:

答案 0 :(得分: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

答案 1 :(得分: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:用于(LexicalDeclaration表达式; Expression)语句

     
      
  1. 让oldEnv成为正在运行的执行上下文的LexicalEnvironment。

  2.   
  3. 让loopEnv为NewDeclarativeEnvironment(oldEnv)。

  4.   
     

[...]

     
      
  1. 让boundNames为LexicalDeclaration的BoundNames。

  2.   
  3. 对于boundNames [..]的每个元素dn

         

    执行! loopEnvRec.CreateImmutableBinding(dn,true)。

  4.   
  5. 将运行中的执行上下文的LexicalEnvironment设置为loopEnv。

  6.   
  7. 让Dcl是评估LexicalDeclaration的结果。

  8.   
     

[...]

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

TLDR:不仅示例是错误的,而且段落也是如此。

答案 2 :(得分:2)

您将x初始化两次,因此出现错误。将一个x重命名为i

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

答案 3 :(得分: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/

包括暂时性盲区的引入。

是的,这本书 now 是不正确的;因为您正在尝试执行以下操作:

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

答案 4 :(得分: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);