函数声明可提前调用且只能出现在顶层或函数体内,函数表达式仅变量声明提升、可置于任意表达式位置;前者名称全局绑定,后者名称仅为内部标识;声明不能立即执行,表达式可以。

在全局执行上下文中,函数声明和函数表达式最直接的区别体现在“能不能提前用”和“能不能随便放”这两点上。
提升行为完全不同
函数声明会被**完全提升**:整个函数定义(包括名字和函数体)在代码执行前就进入全局作用域,所以可以先调用、后声明。
函数表达式只提升**变量声明部分**(如 var fn),赋值动作(= function() {...})仍保留在原位置。调用它必须等赋值完成,否则会报 TypeError: fn is not a function。
-
函数声明可提前调用:
sayHi(); function sayHi() { console.log('Hi'); }→ 正常输出 -
函数表达式不可提前调用:
sayBye(); var sayBye = function() { console.log('Bye'); };→ 报错
语法位置有硬性限制
函数声明只能出现在**脚本顶层**或**函数体内**,不能直接写在 if、for、try 等块级语句中——哪怕写进去,非严格模式下行为不一致,严格模式下直接语法错误。
函数表达式没有这个限制,它可以出现在任何表达式能出现的地方:
- 作为变量赋值的右值(
const f = function() {}) - 作为对象属性(
obj.method = function() {}) - 作为参数传入(
[1,2].map(function(x) { return x * 2; })) - 放在 if 分支里动态创建(
if (x) { const fn = function() {}; })
名称绑定方式不同
函数声明的名称是**作用域绑定的标识符**,在全局作用域中会创建一个同名变量,指向该函数。
函数表达式中的名字(如果写了)只是**内部名称**,仅用于调试栈显示或函数内递归,外部无法访问:
-
function greet() {}→ 全局可访问greet -
const f = function hello() {}→hello在外部不可用,但f.name是"hello"
立即执行场景不兼容
函数声明不能直接加 () 执行,因为解析器会把它当作非法语句:
-
function(){}();→ 语法错误 -
(function(){})();→ 合法,括号让解析器识别为表达式 -
const f = function(){}();→ 合法,赋值语句右侧强制按表达式处理
这种差异本质上源于 JavaScript 引擎对语句(Statement)和表达式(Expression)的不同解析规则。


















