作用域 - [[scope]]

GO - 全局执行上下文

AO - 函数执行上下文

let/const - 块级作用域 { }

  1. 不能在同一作用域下重复声明 {let a = 1; let a = 2;}
  2. 不会跟 var 一样声明提升,会产生一个 TDZ (暂时性死区)
    1. TDZ - Temporal Dead Zone 暂时性死区
  3. 只能在当前的作用域下生效
  4. const 一旦定义必须赋值,并且值不能被更改

!!!特别注意

函数的参数区域() 内也会有自己的作用域

里面的参数声明也会有暂时性死区

TDZ 示例

  1. // 报错 SyntaxError: Identifier 'a' has already been declaredfunction
  2. test(a) {
  3. let a = 1
  4. }
  5. test()
  1. var a = a // 因为 var 声明会变量提升
  2. console.log(a); // undefined
  3. let b = b // 使用 let 声明则不会变量提升,如果在声明赋值前会产生一个 TDZ
  4. console.log(b); // 报错
  1. // 在函数的参数声明中也是如此,所以我们可以把函数的参数声明也看做成是一个独立的作用域
  2. function test(x = y, y = 2) {
  3. console.log(x, y);
  4. }

借用块级作用域的特性,可以很好的解决 var 声明在函数作用域以及全局作用域的属性覆盖问题

  1. for (var i = 0; i < 10; i++) {
  2. setTimeout(
  3. () => {
  4. console.log(i) // 10 个 10
  5. }, 0);
  6. }
  7. for (let i = 0; i < array.length; i++) {
  8. setTimeout(
  9. () => {
  10. console.log(i) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  11. }, 0);
  12. }

因为 var 不受块级作用域的限制,所以他会逐级往外提升。

let 声明碰到已经声明过的变量名则会报错

  1. // 报错 Identifier 'a' has already been declared
  2. {
  3. let a = 1
  4. {
  5. var a = 10
  6. console.log(a);
  7. }
  8. }

var 声明会逐级往外提升,但他不会入侵到块级作用域内部

所以这里的报错原因是 x 的 let 声明 引用了自己的变量 x,而 x 这时还未被声明成功,所以导致报错

  1. var x = 1
  2. {
  3. let x = x // 报错原因在这里
  4. }

函数参数内部的作用域

  1. let x = 1
  2. function foo(x, y = function () { x = x },) {
  3. y() // 此时函数中的 x 抓住的是参数中的 x 所以外部的 x 依然等于 1
  4. // 如果将 参数 x 和 y 的位置的调换则会报错
  5. console.log(x); // undefined
  6. }
  7. console.log(x); // 1
  8. foo(2)