变量提升只提升var声明(不包括赋值),let/const虽声明提升但受TDZ限制,访问会报错;var函数作用域且可重复声明,let/const块级作用域且不可重复声明。

变量提升(Hoisting)到底提升了什么?
JavaScript 中的“变量提升”不是把变量声明和赋值一起挪到顶部,而是只把 var 声明部分(不包括初始化)移到当前作用域顶部,赋值仍保留在原位置。这意味着你能在声明前访问 var 变量,但值是 undefined,而不是报错。
常见错误现象:
- 以为
console.log(a)会报ReferenceError,结果输出undefined - 在函数内用
var声明同名变量,意外覆盖了外层变量却没察觉
console.log(a); // undefined var a = 123;
let 和 const 为什么不再“提升”?
它们确实也经历了声明提升,但被放入了「暂时性死区」(Temporal Dead Zone, TDZ)。也就是说:声明被提升,但直到实际执行到那行代码前,都不能读写该变量——任何访问都会抛出 ReferenceError。
关键区别在于:TDZ 强制你必须「先声明、后使用」,而 var 允许「先用、后声明」(只是值为 undefined)。
立即学习“Java免费学习笔记(深入)”;
使用场景提醒:
- 函数参数默认值中引用
let/const声明的变量,会立即触发 TDZ 错误 -
for循环中用let声明计数器,每次迭代都有独立绑定,避免闭包陷阱 -
const声明的对象属性仍可修改,它只限制「重新赋值」,不冻结内容
console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 456;
var、let、const 的作用域与重复声明规则
三者的作用域行为差异比提升更直接影响代码逻辑:
-
var是函数作用域(或全局),允许重复声明;在块(如if或for)中声明会被提升到函数顶部 -
let和const是块级作用域,不允许重复声明(同一作用域下),且const必须初始化 -
var在全局作用域下会成为window属性(浏览器环境),let/const不会
if (true) {
var x = 1;
let y = 2;
}
console.log(x); // 1 —— var 被提升到函数/全局作用域
console.log(y); // ReferenceError —— y 只存在于 if 块内
容易被忽略的细节:函数声明 vs 函数表达式
函数声明(function foo() {})会被完全提升(声明 + 定义),而函数表达式(const foo = function() {})按 const 规则处理,受 TDZ 约束。
这也意味着:
- 用
var写函数表达式(var foo = function() {})只会提升var foo,foo值仍是undefined,直到执行到赋值行 - 箭头函数始终是表达式,无论用
let还是const声明,都遵循 TDZ - 类声明(
class Foo {})也受 TDZ 约束,不能在声明前使用
真正要警惕的,不是“有没有提升”,而是“提升后能不能安全访问”。let 和 const 把隐式错误变成了显式报错,但前提是你要意识到自己正处在块内、参数默认值里,或者 eval 上下文中——这些地方 TDZ 的边界并不总是直观。











