作用域 - [[scope]]
GO - 全局执行上下文
AO - 函数执行上下文
let/const - 块级作用域 { }
- 不能在同一作用域下重复声明 {let a = 1; let a = 2;}
- 不会跟 var 一样声明提升,会产生一个
TDZ (暂时性死区) - TDZ - Temporal Dead Zone 暂时性死区
- 只能在当前的作用域下生效
- const 一旦定义必须赋值,并且值不能被更改
!!!特别注意
函数的参数区域() 内也会有自己的作用域
里面的参数声明也会有暂时性死区
TDZ 示例
// 报错 SyntaxError: Identifier 'a' has already been declaredfunctiontest(a) {let a = 1}test()
var a = a // 因为 var 声明会变量提升console.log(a); // undefinedlet b = b // 使用 let 声明则不会变量提升,如果在声明赋值前会产生一个 TDZconsole.log(b); // 报错
// 在函数的参数声明中也是如此,所以我们可以把函数的参数声明也看做成是一个独立的作用域function test(x = y, y = 2) {console.log(x, y);}
借用块级作用域的特性,可以很好的解决 var 声明在函数作用域以及全局作用域的属性覆盖问题
for (var i = 0; i < 10; i++) {setTimeout(() => {console.log(i) // 10 个 10}, 0);}for (let i = 0; i < array.length; i++) {setTimeout(() => {console.log(i) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 0);}
因为 var 不受块级作用域的限制,所以他会逐级往外提升。
当 let 声明碰到已经声明过的变量名则会报错
// 报错 Identifier 'a' has already been declared{let a = 1{var a = 10console.log(a);}}
var 声明会逐级往外提升,但他不会入侵到块级作用域内部
所以这里的报错原因是 x 的 let 声明 引用了自己的变量 x,而 x 这时还未被声明成功,所以导致报错
var x = 1{let x = x // 报错原因在这里}
函数参数内部的作用域
let x = 1function foo(x, y = function () { x = x },) {y() // 此时函数中的 x 抓住的是参数中的 x 所以外部的 x 依然等于 1// 如果将 参数 x 和 y 的位置的调换则会报错console.log(x); // undefined}console.log(x); // 1foo(2)
