函数声明可提前调用,函数表达式必须先定义再使用:前者提升名字和函数体,后者仅提升变量名且赋值后才可用;声明只能在顶层或函数内,表达式可任意位置;声明名全局绑定,表达式名仅内部有效;声明需调用才生成闭包,表达式可立即执行创建闭包。

函数声明能提前调用,函数表达式必须先定义再使用——这是最直接影响代码行为的区别。
提升行为完全不同
函数声明在代码执行前就被整个“搬”到作用域顶部,名字和函数体都可用:
- function foo() { console.log(1); } → foo() 写在声明前面也能运行
-
var bar = function() { console.log(2); }; → bar() 写在赋值前会报
TypeError: bar is not a function -
const baz = () => {}; → baz() 写在声明前直接报
ReferenceError(暂时性死区)
语法位置和使用场景不同
函数声明只能出现在脚本顶层或函数体内,不能直接塞进 if、for 里;函数表达式则哪儿都能用:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 函数声明不能这样写:
if (ok) { function doIt() {} }(非标准,行为不一致) - 函数表达式可以:
const handler = condition ? () => 'yes' : () => 'no'; - 可作为参数传入:
[1,2,3].map(function(x) { return x * 2; }) - 支持立即执行:
(function() { console.log('run once'); })();
名称绑定方式有本质差异
函数声明的名字是作用域内正式绑定的标识符;函数表达式的名称(如果有)仅限函数内部使用:
-
function greet() {} →
greet在外部可访问,typeof greet === 'function' -
const fn = function sayHi() { console.log(sayHi); }; →
sayHi在外部不存在,typeof sayHi报错 -
fn.name是'sayHi',但这个名称只是函数对象的属性,不创建额外绑定
闭包与执行时机也跟着变
函数声明定义的是一个“模板”,调用时才生成闭包实例;函数表达式常在赋值那一刻就构造闭包:
-
function makeCounter() { let n = 0; return () => ++n; }→ 需显式调用makeCounter()才得闭包 -
const counter = (() => { let n = 0; return () => ++n; })();→ 定义即执行,立刻拿到闭包函数 - 后者更适合一次性初始化私有状态,比如模块导出、事件处理器工厂
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










