javascript声明提升本质是执行上下文创建阶段对声明的预处理:函数声明整体进入变量对象可提前调用;var声明仅名入vo值为undefined;let/const声明入vo但处于暂时性死区,访问即报错。

JavaScript 声明提升(hoisting)不是代码被“挪到顶部”,而是执行上下文在创建阶段对声明进行预处理的结果。这个过程发生在任何一行可执行代码运行之前,是引擎解析阶段的内在行为。
创建阶段做了三件事
当函数被调用或脚本开始执行时,JavaScript 引擎会为当前作用域创建一个执行上下文(Execution Context),并立即进入创建阶段。此时它会:
- 初始化 变量对象(VO):包括参数(arguments)、函数声明、var 变量声明;
- 建立 作用域链:把当前 VO 和外层作用域的 VO 连起来;
- 确定 this 的值。
不同声明在 VO 中的处理方式
变量对象是提升发生的“容器”。不同声明类型在创建阶段的处理逻辑不同:
- function 声明:整个函数名 + 函数体被放入 VO,可立即调用;
-
var 声明:变量名被放入 VO,初始值设为
undefined; -
let/const 声明:变量名也被放入 VO,但状态标记为“未初始化”,访问即抛出
ReferenceError(TDZ); - 函数表达式 / 箭头函数:不被视为声明,只按普通赋值处理,右侧函数体不会进 VO。
为什么顺序写在后面也能提前用
因为提升发生在创建阶段,而这个阶段不依赖代码书写顺序。引擎会先扫描整块作用域,统一收集所有 function 和 var 声明,再一次性注册进 VO。例如:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
function foo() { return 'a'; }<br>var bar;<br>foo(); // ✅ 成功<br>console.log(bar); // undefined
即便把 function foo() 写在 var bar 后面,创建阶段仍会先注册函数,再注册 var —— 函数声明优先级高于 var 声明。
执行阶段才真正“干活”
创建阶段结束后,才进入执行阶段:逐行运行语句,给 var 赋值、执行函数调用、遇到 let/const 声明才解除 TDZ……所以:
-
console.log(a); var a = 1;不报错,输出undefined(VO 中已有 a,值是 undefined); -
console.log(b); let b = 2;报错(VO 中 b 存在但不可访问,处于 TDZ); -
baz(); var baz = function() {};报错(VO 中只有baz: undefined,没有函数体)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










