JavaScript 中的 hoisting 是声明在编译阶段被提前注册而非代码上移,var 初始化为 undefined,let/const 进入 TDZ 访问即报错,函数声明完全提升而表达式仅提升变量名。
JavaScript 中的 hoisting 不是“把代码往上挪”,而是变量和函数声明在编译阶段被提前“注册”到当前作用域中,但赋值行为仍保留在原地。这意味着 var 声明的变量会初始化为 undefined,而 let/const 声明则进入“暂时性死区”(TDZ),访问会直接报错。
var 的 hoisting 包含声明 + 初始化(默认为 undefined),但不包括赋值。所以即使在声明前读取,也不会报错,只是拿到一个无意义的初始值。
console.log(a); var a = 1; 输出 undefined,而非 ReferenceError 或 1
var a; console.log(a); a = 1;
var a 不会报错,只会被忽略——多次声明等同于一次let 和 const 声明会被 hoist,但不会初始化;从作用域头部到声明语句之间这段区域就是 TDZ。在此区域内访问变量,JS 引擎抛出 ReferenceError。
console.log(b); let b = 2; → 报错 ReferenceError: Cannot access 'b' before initialization
const 还额外要求必须在声明时赋值,否则语法错误:const c; 直接无法通过解析
console.log,也影响 typeof:typeof d 在声明前也会触发 ReferenceError函数声明(function foo() {})完整 hoist:声明 + 定义都提前;函数表达式(var bar = function() {})只 hoist 变量名,不 hoist 赋值,因此不能在定义前调用。
foo(); // OK
function foo() { return 'hoisted'; }TypeError:bar(); // TypeError: bar is not a function
var bar = function() { return 'not hoisted'; };class 在语法上更接近 let:声明会被 hoist,但未到声明位置前访问会报 ReferenceError;且不允许重复声明,哪怕用 var 也不行。
new MyClass(); // ReferenceError
class MyClass {}var MyClass = 42; class MyClass {} → SyntaxError(Identifier 'MyClass' has already been declared)class Child extends Parent 中 Parent 必须在 Child 声明前完成初始化最容易被忽略的是 TDZ 的边界并不总等于大括号块——它由词法环境创建时机决定,比如 for (let i...) 中每个迭代都有独立 TDZ,而 var i 则共享同一个变量。实际写代码时,别依赖 hoisting 去“提前用”,老老实实把声明放在使用之前最稳妥。