let 和 const
let 和 const
  let
    基本用法
      类似var，用于声明变量
      但是所声明的变量，具有块级作用域
      for循环很合适使用let
        for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
      注意：for循环还有一个特别之处，就是设置循环变量的那部分是一个父作用域，而循环体内部是一个单独的子作用域。
        for (let i = 0; i < 1; i++) {
let i = 'abc';
console.log(i);
}
// abc
    不存在变量提升
    存在暂时性死区 TDZ
      暂时性死区的本质就是，只要一进入当前作用域，所要使用的变量就已经存在了，但是不可获取，只有等到声明变量的那一行代码出现，才可以获取和使用该变量
    不允许重复声明
      let不允许在相同作用域内，重复声明同一个变量
      不能在函数内部重新声明参数
  块级作用域
    为什么需要块级作用域？
      第一种场景，内层变量可能会覆盖外层变量
      第二种场景，用来计数的循环变量泄露为全局变量
    let实际上为 JavaScript 新增了块级作用域
    块级作用域可以任意嵌套
    内层作用域可以定义外层作用域的同名变量
    块级作用域的出现，使得匿名立即执行函数表达式（匿名 IIFE）变得不再必要了
  块级作用域与函数声明
    ES5 规定，函数只能在顶层作用域和函数作用域之中声明，不能在块级作用域声明
      // 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// ...
}
      两种函数声明，根据 ES5 的规定都是非法的
    浏览器没有遵守这个规定，为了兼容以前的旧代码，还是支持在块级作用域之中声明函数，因此上面两种情况实际都能运行
    ES6 引入了块级作用域
      明确允许在块级作用域之中声明函数
      函数声明类似于var，即会提升到全局作用域或函数作用域的头部
      函数声明还会提升到所在的块级作用域的头部
      因此在ES6中，块级作用域内声明的函数，行为类似于var声明的变量
    注意：块级作用域必须有大括号
  const
    基本用法
      用于声明一个只读的常量
      一旦声明，常量的值就不能改变
      因此，const声明变量必须立即初始化
      const与let具有相似点
        具有块级作用域
        不存在变量提升
        存在TDZ
        当前作用域中不能重复声明
    本质
      const实际上保证的，并不是变量的值不得改动，而是变量指向的那个内存地址所保存的数据不得改动
      因此const声明的变量，可以改变对象里面的东西
      如果真的想将对象冻结，可以使用Object.freeze
  ES6 声明变量的六种方法
    var命令和function命令
    let和const命令
    import命令和class命令
  顶层对象的属性
    顶层对象，在浏览器环境指的是window对象，在 Node 指的是global对象
    ES5 之中，顶层对象的属性与全局变量是等价的
      缺点
        没法在编译时就报出变量未声明的错误，只有运行时才能知道
        程序员很容易不知不觉地就创建了全局变量
        顶层对象的属性是到处可以读写的，这非常不利于模块化编程
        顶层对象是一个有实体含义的对象，也是不合适的
    ES6 开始，全局变量将逐步与顶层对象的属性脱钩
      一方面规定，为了保持兼容性，var命令和function命令声明的全局变量，依旧是顶层对象的属性
      另一方面规定，let命令、const命令、class命令声明的全局变量，不属于顶层对象的属性
  globalThis 对象
    JavaScript 语言存在一个顶层对象，它提供全局环境（即全局作用域），所有代码都是在这个环境中运行
    顶层对象在各种实现里面是不统一的
      浏览器里面，顶层对象是window
      Web Worker 里面，self也指向顶层对象
      Node 里面，顶层对象是global
    为了能够在各种环境，都能取到顶层对象，现在一般是使用this关键字，但是有局限性
    ES2020 在语言标准的层面，引入globalThis作为顶层对象
      也就是说，任何环境下，globalThis都是存在的，都可以从它拿到顶层对象，指向全局环境下的this