函数声明和函数表达式的核心差异在于提升行为、语法位置、命名可见性及使用场景:声明整块提升且名体俱全,可先调用后定义;表达式仅变量名提升(var)或不提升(let/const),名称仅内部可用,适用于回调、IIFE等需值语义的场合。

函数声明和函数表达式表面都是定义函数,但关键差异在于“什么时候绑定”和“能不能提前用”。它们不是写法偏好问题,而是行为逻辑完全不同。
提升行为:整块提升 vs 名字空挂
函数声明在代码执行前就完成整个函数的注册——名字和函数体一起被提到作用域顶部,所以可以先调用后写:
-
✅ 正常运行:
say(); function say() { console.log('hi'); } -
❌ 报错(var):
fn(); var fn = function() {}; // fn 是 undefined -
❌ 报错(let/const):
fn(); let fn = () => {}; // ReferenceError,直接进暂时性死区
语法位置:必须独立 vs 随处可嵌
函数声明只能出现在顶层或函数体内,不能直接塞进 if、for、try 等块级结构里(严格模式下会报错,非严格模式行为不一致):
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
✅ 合法:
function foo() {}或function bar() { function inner() {} } -
❌ 应避免:
if (true) { function baz() {} } -
✅ 函数表达式自由得多:
if (ok) { const h = function() {}; },[1,2].map(function(x) { return x * 2; })
命名与作用域:对外可见 vs 对内私有
函数声明的名字是作用域内的正式标识符,外部可访问;函数表达式的名称(如果写了)仅用于内部递归或调试栈显示,外部不可见:
立即学习“Java免费学习笔记(深入)”;
-
✅ 声明可直接用名:
function greet() {}; typeof greet === 'function' -
✅ 表达式内部可用名:
const talk = function hello() { console.log(hello); }; talk(); -
❌ 表达式外部不可用名:
hello(); // ReferenceError -
✅ name 属性保留内部名:
talk.name // 'hello'
典型使用场景:主流程 vs 回调与封装
函数声明适合定义模块级、可复用的核心逻辑;函数表达式更适合需要值语义的场合:
- 声明常用在: 全局工具函数、类方法骨架、导出主函数
-
表达式常用在: 事件监听器、数组遍历回调、IIFE(如
(function(){})())、闭包封装、动态生成函数 - IIFE 必须用表达式: 括号、加号、感叹号等运算符强制解析为表达式,否则会被当作声明而报错

















