JavaScript中不存在“作用域提升”,实际是声明提升:函数声明完整提升并优先于var声明,后者仅提升声明不提升赋值;let/const不提升且受TDZ限制。

JavaScript 中并不存在“作用域提升”这个概念——真正发生的是函数声明和变量声明在执行上下文创建阶段的提升(Hoisting),而函数声明的提升优先级高于 var 变量声明。所谓“函数优先于变量加载”,本质是 JS 引擎在编译阶段对同名标识符处理的顺序规则。
函数声明会完整提升,var 变量只提升声明不提升赋值
在全局或函数作用域的「创建阶段」,JS 引擎会:
- 先扫描所有
function name() { ... }声明,把整个函数体绑定到变量环境中,键名为name,值为函数对象; - 再扫描所有
var name声明,如果该name已被函数声明占用,则跳过(不会重复声明); - 若后续出现
var name = ...赋值语句,则是在执行阶段覆盖已有绑定。
同名时,函数声明“赢在起跑线”,但会被赋值覆盖
看这段代码的实际行为:
console.log(a); // function a() {}var a = 10;
function a() {}
console.log(a); // 10
它不是靠“作用域”决定谁先加载,而是执行上下文的变量环境在创建阶段就已确定:a 初始绑定的是函数;执行到 var a = 10 时,只是给已存在的 a 重新赋值。
立即学习“Java免费学习笔记(深入)”;
let/const 完全不参与这种“优先级竞争”
let 和 const 声明不会被提升到作用域顶部,它们存在暂时性死区(TDZ):
- 从进入块级作用域开始,到声明语句执行前,访问该变量直接报
ReferenceError; - 即使有同名函数声明,
let a = ...出现在function a() {}前面,也会导致语法错误或运行时报错,因为 TDZ 阻断了任何提前访问。
别混淆:提升发生在作用域内部,但不是“作用域”本身被提升
作用域是静态的、词法确定的结构,不会被“提升”。真正被处理的是作用域中声明的绑定(binding):
- 函数声明 → 绑定到变量环境,值为函数;
-
var声明 → 绑定到变量环境,初始值为undefined(若未被函数覆盖); -
let/const声明 → 绑定到词法环境,但处于 TDZ,不可访问。


















