函数声明会被完整提升,函数表达式只提升变量名(var下)或根本不提升(let/const下);前者整个函数体提前可用,后者仅var声明提升变量为undefined,let/const则存在暂时性死区。

函数声明会被完整提升,函数表达式只提升变量名(var 声明下)或根本不提升(let/const 下)——这是最直接的区别。
函数声明:整个函数体提前可用
只要语法是 function name() { ... } 这种形式,JS 引擎就会在编译阶段把函数名和函数体一起移到当前作用域顶部。所以你可以在声明之前调用它:
foo(); // ✅ 输出 "I'm declared"function foo() { console.log("I'm declared"); }
这背后没有“先声明后赋值”的拆分逻辑,而是整块定义被提前注册。
函数表达式:只提升变量声明(仅限 var)
当你写 var bar = function() { ... };,JS 只把 var bar; 提升,bar 初始值为 undefined,函数体仍留在原地:
立即学习“Java免费学习笔记(深入)”;
bar(); // ❌ TypeError: bar is not a functionvar bar = function() { console.log("I'm expressed"); };
等价于:
var bar; // 提升,bar === undefinedbar(); // 尝试调用 undefinedbar = function() { ... }; // 赋值发生在这一行
let/const 声明的函数表达式:不提升,有暂时性死区
用 let 或 const 定义函数表达式时,变量不会被提升到作用域顶部,而是在声明前处于“暂时性死区”(TDZ):
baz(); // ❌ ReferenceError: Cannot access 'baz' before initializationconst baz = () => console.log("arrow");
箭头函数、方法简写(如 obj = { method() {} })、类中方法都属于函数表达式范畴,全部遵循这一规则。
命名函数表达式:名字不对外暴露
像 const fn = function named() { ... }; 这样的写法,named 只在函数内部可用(用于递归或调试),外部无法访问:
console.log(fn); // ✅ 函数本身console.log(named); // ❌ ReferenceError
它的提升行为完全由变量声明方式(var/let/const)决定,和内部名字无关。


















