JavaScript变量声明在编译阶段通过“提升”实现:var声明仅登记变量名并初始化为undefined,function声明则同时登记并绑定函数对象,let/const登记但不初始化,处于TDZ中。

JavaScript 中变量声明在编译阶段的执行过程,核心在于“提升”(Hoisting)——它不是代码被物理移动,而是引擎在真正执行前,先扫描并登记声明,为后续执行铺好环境。
编译阶段会做三件事
当一段 JS 代码(比如全局脚本或函数体)即将运行时,V8 引擎先暂停执行,进入编译阶段。这个阶段不运行任何赋值或逻辑,只做静态准备:
- 创建执行上下文(Execution Context),包含变量环境(Variable Environment)和词法环境(Lexical Environment)两个关键结构
- 扫描所有 var 声明,把变量名作为 key 加入变量环境,初始值设为 undefined
- 扫描所有 function 声明(注意:仅限
function name() {...}这种形式),把函数名加入变量环境,值直接指向完整函数对象
var 和 function 提升行为不同,原因在这里
虽然都叫“提升”,但本质处理方式不同:
-
var 只提升声明:比如
var a = 123;,编译阶段只记下a: undefined;真正的= 123要等到执行阶段才发生 -
function 提升声明 + 定义:比如
function foo() { return 'ok'; },编译阶段就已把整个函数体挂到foo名下,所以能先调用后写 - 如果同名,function 声明会覆盖 var 声明(但不会覆盖后面的 var 赋值),这是编译阶段按顺序处理的结果
let/const 不是“不提升”,而是“不初始化”
ES6 的 let 和 const 也会在编译阶段被登记进词法环境,但不会赋初始值 —— 它们处于“暂时性死区”(TDZ)中,直到执行阶段真正走到声明那行代码才初始化。因此,在声明前访问会直接报 ReferenceError,而不是返回 undefined。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
一个典型例子还原编译全过程
看这段代码:
console.log(a); // undefined
console.log(b); // 报错:ReferenceError
foo(); // 正常输出 'hello'
bar(); // 报错:TypeError(bar 是 undefined)
var a = 10;
let b = 20;
function foo() { console.log('hello'); }
var bar = function() {};
编译阶段完成后,变量环境大致是:
-
a: undefined(var 声明登记) -
foo: [Function: foo](function 声明登记) -
bar: undefined(var 声明登记,但此时还没赋函数表达式)
而 b 已被记录在词法环境中,但尚未初始化,所以第一行访问就触发 TDZ 报错。

















