JavaScript变量提升指var声明和function声明在解析阶段被提前注册到作用域,但仅声明提升、赋值不提升;var变量初始化为undefined,故访问未赋值变量得undefined而非报错,而let/const存在TDZ,访问即报错。

JavaScript 变量提升(Hoisting)不是把代码“挪到上面”,而是指 var 声明的变量和 function 声明会被**解析阶段提前注册进当前作用域**,但只有声明被提升,赋值不会。
为什么用 var 时能访问未声明的变量却不报错?
因为变量在进入执行上下文时已被初始化为 undefined。这不是“运行时跳过错误”,而是语言规范定义的绑定行为。
-
var a = 1实际分两步:声明(提升)→ 赋值(不提升) - 所以在声明语句前访问
a,得到的是undefined,不是ReferenceError - 而
let和const不会初始化为undefined,它们有“暂时性死区”(TDZ),访问即报错
console.log(a); // undefined var a = 1; console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 2;
function 声明和 function 表达式提升区别在哪?
只有 function 声明(即以 function 关键字开头、带函数名的完整声明)会被完全提升(声明 + 函数体);function 表达式只提升变量名(如果是 var),函数体不提升。
-
foo()在声明前调用成功 → 是function foo() { ... } -
bar()在声明前调用报TypeError→ 是var bar = function() { ... } - 箭头函数、
class都属于“不可提升”的语法结构,行为同let
foo(); // OK → "I'm hoisted"
function foo() {
console.log("I'm hoisted");
}
bar(); // TypeError: bar is not a function
var bar = function() {
console.log("I'm not fully hoisted");
};
ES6 之后还用得着关心变量提升吗?
必须关心——因为 var 仍广泛存在于旧代码、全局污染场景、某些循环闭包写法中;更重要的是,let/const 的 TDZ 行为容易被误判为“没提升”,其实它也有提升(绑定已注册),只是拒绝访问。
立即学习“Java免费学习笔记(深入)”;
- 混淆点:很多人以为
let“不提升”,实际是提升但不可读取 -
typeof检查var变量不会报错(返回"undefined"),但检查let变量在 TDZ 内会直接抛错 - 模块顶层的
import也受提升影响:所有import都在模块执行前完成,且不可动态加载
最易忽略的一点:提升发生在**每个函数作用域内**,不是全局一锅端;嵌套函数中,内部 var 提升只对内部生效,不影响外层同名变量——但若没加 var,就会意外触发隐式全局,那又是另一类问题了。











