相同情况下不同的未捕获引用错误

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

我不明白为什么对于这些相同的情况控制台会返回两个不同的输出

console.log(a);
let a = 1;

控制台说 a 未定义

还有这里

function a1() {
    console.log(a);
    let a = 1;
}
a1();

控制台显示初始化前无法访问“a” 在这两种情况下不是应该返回“初始化之前无法访问'a'”吗?因为我们使用 let 声明来声明变量,并且在这两种情况下它们都在 TDZ 中?为什么说a未定义?

为什么会有这样的效果?全局范围内的变量提升与块范围内的变量提升不同吗?

javascript scope initialization hoisting uncaught-reference-error
1个回答
0
投票

这只是您使用的控制台处理您粘贴到其中的内容的方式的结果。不要从中吸取任何教训并将其应用到控制台之外。控制台REPL执行的一些操作与代码的实际行为方式略有不同,无论是在全局范围还是函数范围(或模块范围)。控制台 REPL 对于很多事情都很方便,但不要在没有仔细检查的情况下将它们的作用推断到其他环境。

在您的示例中,控制台评估每个语句而不向前扫描到下一个(即使您将行与行之间的换行符粘贴在一起也是如此)。所以首先它评估

console.log(a);
,并且由于没有声明
a
的标识符它为您提供了标准
a is not defined
然后它评估了您的
let a = 1;

但这并不是在全局范围内实际评估代码的方式。如果你有:

console.log(a); let a = 1;
...JavaScript 引擎首先扫描所有代码,查找类似 

let a

 的声明(以及 
var a
function
class
 声明),并为它们创建 
绑定(大致是变量)。现代声明的绑定(let
const
class
)未初始化;旧的 
var
 样式绑定(
var
function
 声明)被初始化(分别使用 
undefined
 或函数)。因此,当它去评估分步代码时,它会看到 
a
declared,但不是 initialized,并给出 Cannot access 'a' before initialization
 错误:

console.log(a); let a = 1;

当您使用函数时,它为您提供了第二种行为,因为该函数在完成之前不会被评估,并且该评估的工作方式与我上面描述的全局评估类似,因此 JavaScript 引擎知道

a

 已声明(但不是初始化)并抛出适当的错误。

© www.soinside.com 2019 - 2024. All rights reserved.