使用 var 声明变量

存在的三个主要问题:

  1. ☑️ 允许重复的变量声明:导致数据被覆盖

  2. ☑️ 变量提升:怪异的数据访问、闭包问题

  3. ☑️ 全局变量挂载到全局对象:全局对象成员污染问题


使用 let 声明变量

ES6 不仅引入 let 关键字用于解决变量声明的问题,同时引入了块级作用域的概念

块级作用域

  • 代码执行时遇到花括号,会创建一个块级作用域

  • 花括号结束,销毁块级作用域

let 解决的问题:

  1. ☑️ 全局变量挂载到全局对象:全局对象成员污染问题

    • let 声明的变量不会挂载到全局对象

  2. ☑️ 允许重复的变量声明:导致数据被覆盖

    • let 声明的变量,不允许当前作用域范围内重复声明

    • 在块级作用域中用 let 定义的变量,在作用域外不能访问

  3. ☑️ 变量提升:怪异的数据访问、闭包问题

    • 使用 let 不会有变量提升,因此不能在定义 let 变量之前使用它

    • 底层实现上,let 声明的变量实际上也会有提升,但是提升后会将其放入到"暂时性死区"

    • 如果访问的变量位于暂时性死区,则会报错:"Cannot access 'a' before initialization"

    • 当代码运行到该变量的声明语句时,会将其从暂时性死区中移除

循环中的特殊处理:

  • 在循环中,用 let 声明的循环变量会特殊处理

  • 每次进入循环体,都会开启一个新的作用域,并且将循环变量绑定到该作用域(每次循环,使用的是一个全新的循环变量)

  • 在循环中使用 let 声明的循环变量,在循环结束后会销毁


使用 const 声明常量

constlet 完全相同,仅在于用 const 声明的变量:

  • 必须在声明时赋值

  • 不可以重新赋值

推荐使用 const 的原因:

  1. ☑️ 根据经验,开发中的很多变量,都是不会更改,也不应该更改的

  2. ☑️ 后续的很多框架或者是第三方 JS 库,都要求数据不可变,使用常量可以一定程度上保证这一点

注意的细节:

  1. 常量不可变的理解

    • 常量不可变,是指声明的常量的内存空间不可变

    • 并不保证内存空间中的地址指向的其他空间不可变

  2. 常量的命名规范

    • 特殊的常量:该常量从字面意义上,一定是不可变的(比如圆周率、月地距地或其他一些绝不可能变化的配置)

      • 命名规范:通常,该常量的名称全部使用大写,多个单词之间用下划线分割

    • 普通的常量:使用和之前一样的命名即可

  3. 循环中的限制

    • 在 for 循环中,循环变量不可以使用常量


总结

声明方式

重复声明

变量提升

块级作用域

全局对象属性

必需初始值

可重新赋值

var

✅ 允许

✅ 有

❌ 无

✅ 是

❌ 否

✅ 是

let

❌ 不允许

❌ 无

✅ 有

❌ 否

❌ 否

✅ 是

const

❌ 不允许

❌ 无

✅ 有

❌ 否

✅ 是

❌ 否

☑️ 现代开发建议:优先使用 const,只有在确实需要重新赋值时才使用 let,避免使用 var