我不明白为什么对于这些相同的情况控制台会返回两个不同的输出
console.log(a);
let a = 1;
控制台说 a 未定义
还有这里
function a1() {
console.log(a);
let a = 1;
}
a1();
控制台显示初始化前无法访问“a” 在这两种情况下不是应该返回“初始化之前无法访问'a'”吗?因为我们使用 let 声明来声明变量,并且在这两种情况下它们都在 TDZ 中?为什么说a未定义?
为什么会有这样的效果?全局范围内的变量提升与块范围内的变量提升不同吗?
这只是您使用的控制台处理您粘贴到其中的内容的方式的结果。不要从中吸取任何教训并将其应用到控制台之外。控制台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
已声明(但不是初始化)并抛出适当的错误。