
在 JavaScript 中var、let、const都可以声明变量但它们在作用域、变量提升、重复声明、修改值等方面有明显区别。先看一个总表特性varletconst作用域函数作用域块级作用域块级作用域变量提升有可提前访问值是undefined有但存在 TDZ有但存在 TDZ重复声明可以不可以不可以重新赋值可以可以不可以声明时必须赋值不需要不需要必须一、作用域区别var函数作用域var没有真正的块级作用域。if (true) { var a 10 } console.log(a) // 10虽然a写在{}里面但外面依然可以访问。因为var主要受函数作用域限制而不是普通代码块。比如function test() { var a 10 } console.log(a) // 报错这里a只能在test函数内部使用。let 和 const块级作用域let和const都存在块级作用域。if (true) { let a 10 const b 20 } console.log(a) // 报错 console.log(b) // 报错这里的{ }就形成了一个作用域。所以let和const只在当前代码块中有效。二、什么是变量提升JavaScript 在执行代码之前会先处理变量和函数声明。这种现象通常叫变量提升 Hoisting例如console.log(a) var a 10不会报错而是输出undefined可以粗略理解成var a console.log(a) a 10所以var声明会被提升并且初始化为undefined。三、let 和 const 也有变量提升吗有。但是不能在声明之前访问。例如console.log(a) let a 10会直接报错ReferenceErrorconst也是一样console.log(a) const a 10同样报错。所以更准确地说let和const也会被提升但是在真正执行到声明语句之前不能访问。这段区域就叫TDZ暂时性死区 Temporal Dead Zone四、什么是 TDZ例如{ console.log(a) let a 10 }从进入这个作用域开始到执行let a 10之前这一段区域就是a的暂时性死区。可以理解成进入作用域 ↓ TDZ 开始 ↓ console.log(a) // 不能访问 ↓ let a 10 ↓ TDZ 结束 ↓ 之后可以正常使用 a所以不是let完全没有变量提升。而是提升了但在初始化之前不能访问。const同样如此。五、重复声明的区别var可以重复声明var a 10 var a 20 console.log(a) // 20但是let不可以let a 10 let a 20会报错。const也不可以const a 10 const a 20同样报错。所以var → 可以重复声明 let → 不可以 const → 不可以这也是现在更推荐使用let和const的原因之一可以减少变量重复声明带来的问题。六、重新赋值的区别var可以重新赋值var a 10 a 20let也可以let a 10 a 20但是const a 10 a 20会报错。因为const声明以后不能重新给这个变量赋另一个值。七、const 真的完全不能修改吗这是最容易误解的地方。例如const obj { name: Tom } obj.name Jack这是允许的。甚至obj.age 18也是允许的。但是obj {}不允许。为什么因为const限制的是变量本身保存的引用不能改变。不是对象里面的内容完全不能修改。可以这样理解const obj { name: Tom }变量obj保存的是一个对象的引用obj ↓ 对象 { name: Tom }你修改obj.name Jack只是修改对象内部内容。引用没有变化obj ↓ 还是原来的对象所以允许。但如果obj {}相当于obj ↓ 换成另一个对象引用发生变化所以报错。八、const 声明时为什么必须赋值下面这样不行const a因为const创建后不能重新赋值。如果声明的时候不给值后面就没办法再赋值了。所以必须const a 10而let可以let a a 10九、为什么现在不推荐使用 var主要因为var有几个容易产生问题的地方。比如没有块级作用域for (var i 0; i 3; i) { } console.log(i) // 3i跑到了循环外面。而for (let i 0; i 3; i) { } console.log(i) // 报错let的i只存在于循环作用域中。另外var还能重复声明var name Tom var name Jack有时候可能不小心覆盖前面的变量。所以现代 JavaScript 基本推荐优先 const ↓ 需要重新赋值时用 let ↓ 尽量不用 var十、let 和 const 怎么选择可以记一个非常实用的原则默认使用 const需要重新赋值时再改成 let。比如const user { name: Tom }对象本身不会换掉用const如果let count 0 count因为count会变化所以用let十一、面试最容易问的几个点1. var 和 let 最大区别是什么可以答var是函数作用域let是块级作用域var可以重复声明并且声明提升后值为undefined而let存在暂时性死区声明前不能访问。2. let 有变量提升吗有。只是提升后没有立即初始化声明前处于 TDZ所以不能访问。3. const 对象为什么还能修改因为const限制的是变量绑定也就是引用地址不能重新赋值不限制对象内部属性修改。例如const obj {} obj.a 1 // 可以 obj {} // 不可以总结var、let、const最核心的区别可以压缩成var → 函数作用域 → 可以重复声明 → 可以重新赋值 → 声明提升后是 undefinedlet → 块级作用域 → 不能重复声明 → 可以重新赋值 → 存在 TDZconst → 块级作用域 → 不能重复声明 → 不能重新赋值 → 存在 TDZ → 声明时必须赋值最后记住两个最重要的点let/const都有变量提升只是存在 TDZ。以及const不是“值完全不能变”而是“变量不能重新指向另一个值”。实际开发中建议默认 const 需要重新赋值 → let 尽量不用 var