JavaScript中变量提升(Hoisting)分三类:函数声明完整提升,可提前调用;var仅声明提升、赋值保留,访问得undefined;let/const声明提升但处于暂时性死区,提前访问报ReferenceError。

JavaScript 中没有“作用域提升”这个术语,准确说法是 变量提升(Hoisting) 和 函数提升,它们都发生在编译阶段,但处理方式和结果完全不同。理解差异的关键不在“谁升得更高”,而在于“怎么升、升什么、能不能用”。
函数声明会被完整提升,声明前就能调用
函数声明(function foo() { ... })在编译阶段不仅把函数名注册进作用域,还把整个函数体一并绑定到该标识符上。因此,调用可以出现在声明之前,不会报错,也能正常执行。
sayHi(); // 正常输出 "Hi"function sayHi() { console.log("Hi"); }
这等价于编译后立即存在:function sayHi() { console.log("Hi"); },后续调用直接命中。
var 变量只提升声明,不提升赋值,访问得 undefined
var 声明的变量在编译阶段仅将变量名加入作用域,并初始化为 undefined;真正的赋值语句仍保留在原位置,等到执行阶段才运行。
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
console.log(age); // undefinedvar age = 25;
引擎实际按如下顺序执行:var age; → console.log(age); → age = 25;。注意:不是“移动代码”,而是编译时已分配内存并设默认值。
函数表达式按变量规则处理,声明前访问是 undefined
像 var greet = function() { ... }; 这类写法,本质是「var 声明 + 函数赋值」。编译阶段只提升 var greet(值为 undefined),函数体要等到执行到赋值那行才会创建。
greet(); // TypeError: greet is not a functionvar greet = function() { console.log("Hello"); };
因为此时 greet 是 undefined,不是函数,无法调用。
let/const 也提升,但进入暂时性死区(TDZ)
let 和 const 的声明同样在编译阶段被识别并绑定到作用域,但不会初始化任何值——从作用域顶部到声明语句之间,属于「暂时性死区」。
console.log(name); // ReferenceError: Cannot access 'name' before initializationlet name = "Alice";
这和 var 的 undefined 行为有本质区别:不是值未定义,而是语法上禁止访问。

















