Hoisting在javascript中如何工作_变量提升有何陷阱【教程】

13次阅读

javaScript 中的 hoisting 是声明在编译阶段被提前注册而非代码上移,var 初始化为 undefined,let/const 进入 TDZ 访问即报错,函数声明完全提升而表达式仅提升变量名。

Hoisting在javascript中如何工作_变量提升有何陷阱【教程】

javascript 中的 hoisting 不是“把代码往上挪”,而是变量和函数声明在编译阶段被提前“注册”到当前作用域中,但赋值行为仍保留在原地。这意味着 var 声明的变量会初始化为 undefined,而 let/const 声明则进入“暂时性死区”(TDZ),访问会直接报错。

var 声明为何能访问但值是 undefined

var 的 hoisting 包含声明 + 初始化(默认为 undefined),但不包括赋值。所以即使在声明前读取,也不会报错,只是拿到一个无意义的初始值。

  • 常见错误现象:console.log(a); var a = 1; 输出 undefined,而非 ReferenceError1
  • 实际执行逻辑等价于:var a; console.log(a); a = 1;
  • 函数内重复 var a 不会报错,只会被忽略——多次声明等同于一次

let/const 在 TDZ 中访问会立即报错

letconst 声明会被 hoist,但不会初始化;从作用域头部到声明语句之间这段区域就是 TDZ。在此区域内访问变量,js 引擎抛出 ReferenceError

  • 错误示例:console.log(b); let b = 2; → 报错 ReferenceError: Cannot access 'b' before initialization
  • const 还额外要求必须在声明时赋值,否则语法错误:const c; 直接无法通过解析
  • TDZ 不仅影响 console.log,也影响 typeoftypeof d 在声明前也会触发 ReferenceError

函数声明 vs 函数表达式 hoisting 行为完全不同

函数声明(function foo() {})完整 hoist:声明 + 定义都提前;函数表达式(var bar = function() {})只 hoist 变量名,不 hoist 赋值,因此不能在定义前调用。

立即学习Java免费学习笔记(深入)”;

  • 可安全调用:
    foo(); // OK function foo() { return 'hoisted'; }
  • 不可调用,报 TypeError
    bar(); // TypeError: bar is not a function var bar = function() { return 'not hoisted'; };
  • 箭头函数属于函数表达式,同样不具函数声明级 hoisting

class 声明也受 TDZ 约束,且不能被重复声明

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 ParentParent 必须在 Child 声明前完成初始化

最容易被忽略的是 TDZ 的边界并不总等于大括号块——它由词法环境创建时机决定,比如 for (let i...) 中每个迭代都有独立 TDZ,而 var i 则共享同一个变量。实际写代码时,别依赖 hoisting 去“提前用”,老老实实把声明放在使用之前最稳妥。

text=ZqhQzanResources