变量提升是声明在编译阶段被移至作用域顶部的行为,作用域决定变量可访问范围与生命周期;var仅具函数/全局作用域且声明提升、赋值不提升,let/const具块级作用域、不提升且存在暂时性死区。

JavaScript 中变量的“提升”和“作用域”是两个紧密关联但本质不同的概念。理解它们的关键在于:提升(hoisting)是声明在编译阶段被移动到作用域顶部的**行为表现**;而作用域(scope)决定的是**变量在哪里能被访问、生命周期何时开始与结束**。块级作用域和全局作用域对变量提升的影响,主要取决于你用的是 var、let 还是 const。
var 声明:只存在函数作用域或全局作用域,且会被提升
var 没有块级作用域的概念。即使写在 if{} 或 for{} 里,它仍属于外层函数作用域(或全局作用域),并且声明会被提升到该作用域顶部,赋值不会提升。
- 在全局作用域中用
var a = 1,相当于先声明var a(挂载到window.a),再执行a = 1 - 在函数内用
var b,声明会提升到函数开头,但函数外无法访问b - 在
if(true) { var c = 2 }中,c实际上是函数/全局变量,不是“块内私有”
let/const 声明:支持块级作用域,不提升,存在暂时性死区(TDZ)
let 和 const 声明的变量具有真正的块级作用域({}、if、for 等都算),而且不会被提升——更准确地说,它们被“提升”到了块的顶部,但处于暂时性死区,直到声明语句执行前都不可访问。
- 在块外访问
let x声明的变量,直接报ReferenceError - 在声明前访问(如
console.log(x); let x = 5),同样报错,这就是 TDZ 的体现 - 全局作用域中用
let y = 10,它不会成为window.y的属性,也不受变量提升影响
函数作用域 vs 块级作用域:提升行为的“容器”不同
变量提升总是在其**所在作用域的顶部**发生,这个“顶部”取决于作用域类型:
立即学习“Java免费学习笔记(深入)”;
- 对
var来说,“作用域顶部”是最近的函数体开头,或全局脚本最上方 - 对
let/const来说,“作用域顶部”是最近的块({})开头,但该位置不可访问,直到声明执行 - 函数声明(
function foo(){})会完整提升(包括函数体),且优先级高于var声明;而函数表达式(const bar = function(){})按const规则处理,不提升
一个典型对比示例
下面代码清晰展现差异:
console.log(a); // undefined(var 提升,未赋值)
console.log(b); // ReferenceError(let 在 TDZ)
console.log(c); // ReferenceError(const 同样在 TDZ)
var a = 1;
let b = 2;
const c = 3;
if (true) {
var d = 4; // 全局/函数作用域,可从外面访问
let e = 5; // 块级作用域,外部访问报错
}
console.log(d); // 4
console.log(e); // ReferenceError


















