函数声明会被完整提升,可在声明前调用;函数表达式不提升,只能在赋值后使用;声明只能出现在顶层或函数体,表达式可任意嵌套;声明必须命名且名在外层有效,表达式可匿名或具名但名仅函数内有效;声明编译时绑定,表达式执行时创建。

函数声明和函数表达式表面看都是定义函数,但它们在代码执行前的处理方式、可调用时机和使用场景完全不同。
提升行为不一样
函数声明会被完整提升:函数名和函数体一起提前注册到当前作用域,所以能在声明前调用。
-
✅ 可以这样写:
foo(); function foo() { console.log('ok'); } -
❌ 函数表达式不行:
bar(); const bar = function() { console.log('no'); };会报错,因为bar此时还没赋值 -
var声明的函数表达式只提升变量名(值为undefined),let/const则直接进入暂时性死区,访问即报错
语法位置有硬性限制
函数声明只能出现在脚本顶层或函数体内,不能直接写在 if、for、try 这类块级结构里;而函数表达式没有这个限制。
- 函数声明写在
if中属于非标准行为,不同环境表现不一致,严格模式下会报错 - 函数表达式可以自由出现在任意表达式位置:作为参数传入、赋值给对象属性、放在条件分支中、甚至立即执行(IIFE)
- 比如:
[1,2,3].map(function(x){return x*2})或if (x) { fn = function(){...} }
名称绑定逻辑不同
函数声明必须带名字,且该名字在外部作用域中可用;函数表达式可以匿名,也可以命名,但名字只在函数内部生效。
- 函数声明:
function greet() { }→greet在外层可直接调用 - 具名函数表达式:
const f = function hello() { console.log(hello); };→hello在函数内可用(比如递归),但hello()在外面会报ReferenceError - 箭头函数也属于表达式范畴,不提升、无
this、无arguments,但内存创建机制和普通函数表达式一致
本质是执行时机不同
函数声明在编译阶段就完成绑定,函数表达式则等到执行到那行代码时才创建函数对象并赋值。
- 声明阶段:引擎为函数声明预分配作用域绑定,指向已构建好的函数对象
- 执行阶段:函数表达式才真正构造函数对象,并通过变量引用关联,属于动态求值
- 两者在堆内存中都生成 Function 对象,区别在于“谁什么时候把名字连上它”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











