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");
};
必须关心——因为 var 仍广泛存在于旧代码、全局污染场景、某些循环闭包写法中;更重要的是,let/const 的 TDZ 行为容易被误判为“没提升”,其实它也有提升(绑定已注册),只是拒绝访问。
let “不提升”,实际是提升但不可读取typeof 检查 var 变量不会报错(返回 "undefined"),但检查 let 变量在 TDZ 内会直接抛错import 也受提升影响:所有 import 都在模块执行前完成,且不可动态加载最易忽略的一点:提升发生在**每个函数作用域内**,不是全局一锅端;嵌套函数中,内部 var 提升只对内部生效,不影响外层同名变量——但若没加 var,就会意外触发隐式全局,那又是另一类问题了。