我的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”
这本书中的代码不正确吗? (这本书的勘误网站上没有任何内容:)。
答案 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*/;
外部范围中是否还有另一个x
(for
循环中的初始化程序在其自己的范围之内)并不重要,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)语句
让oldEnv成为正在运行的执行上下文的LexicalEnvironment。
让loopEnv为NewDeclarativeEnvironment(oldEnv)。
[...]
让boundNames为LexicalDeclaration的BoundNames。
对于boundNames [..]的每个元素dn
执行! loopEnvRec.CreateImmutableBinding(dn,true)。
将运行中的执行上下文的LexicalEnvironment设置为loopEnv。
让Dcl是评估LexicalDeclaration的结果。
[...]
如您所见,正在运行的执行上下文是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中,发生了一项重大更改,使let
和const
遵循以下标准:
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
,或使用var
。 var
将变量添加到全局范围,因此在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);