javascript提升是什么_变量和函数声明如何被提升?

JavaScript提升是引擎在编译阶段将var和function声明的声明部分提前注册到作用域,但赋值仍保留在原位置;var声明被初始化为undefined,let/const存在暂时性死区,函数声明完全提升而函数表达式仅变量名提升。

JavaScript 提升(Hoisting)到底是什么

提升不是代码被“移动”到顶部,而是 JavaScript 引擎在编译阶段把 var 声明和 function 声明的**声明部分**提前注册到当前作用域中,但赋值或初始化仍保留在原位置。这意味着你可以在声明前访问变量或调用函数,但结果可能出乎意料。

var 声明的提升行为

var 只提升声明,不提升赋值,且会被初始化为 undefined。这是最常踩坑的地方。

  • console.log(a); var a = 1;,输出是 undefined,不是报错
  • console.log(b); let b = 2;,直接抛出 ReferenceError —— letconst 不提升声明(严格来说是存在「暂时性死区」)
  • 重复 var a = 1; var a = 2; 不报错,等价于一次声明 + 两次赋值
console.log(x); // undefined
var x = 10;
console.log(x); // 10

function 声明 vs function 表达式

只有使用 function 关键字开头的**函数声明**才会被完全提升(声明 + 函数体);而函数表达式(如赋值给 var / const)只提升变量名,不提升函数体。

  • foo(); function foo() { ... } ✅ 正常执行
  • bar(); var bar = function() { ... }; ❌ 报 TypeError: bar is not a function(因为 barundefined
  • baz(); const baz = () => {}; ❌ 直接 ReferenceError
hoistedFunc(); // OK: "I'm hoisted"
function hoistedFunc() {
  console.log("I'm hoisted");
}

notHoistedFunc(); // TypeError: notHoistedFunc is not a function
var notHoistedFunc = function() {
  console.log("I'm NOT hoisted");
};

实际开发中该注意什么

提升机制容易掩盖逻辑顺序问题,现代代码应尽量规避依赖它。

  • 始终在使用前声明变量,尤其避免在块级作用域(iffor)里用 var
  • 优先用 const / let 替代 var,它们不参与传统提升,行为更可预测
  • 函数尽量统一用声明形式(若需条件定义,改用 if 内赋值给 const 变量)
  • ES6 模块中,importexport 也存在提升,但必须出现在顶层,不能在条件或函数内
真正麻烦的不是提升本身,而是它让 var 声明看起来像“全局可见”,却在赋值前返回 undefined——这个中间态最容易被忽略。