函数引用与函数执行的区别

3 阅读2分钟

面试官:你在项目研发时,踩过什么坑?

第一层:问题现象

在做软件分发管理系统时,有一个“新增”按钮,点击后应该弹出弹窗,但点了没有任何反应。
代码是这样写的:

<Button onClick={() => onAdd}>新增</Button>

排查了很久,接口没问题,弹窗组件没问题,最后发现问题出在这一行代码本身。


第二层:定位根因

() => onAdd 是一个箭头函数,函数体是 onAdd —— 没有括号

() => onAdd      // 等价于 () => { return onAdd }

点击时 React 调用了这个箭头函数,它只是返回了 onAdd 函数对象本身,返回值被丢弃,onAdd 从始至终没有被执行

修复很简单:

onClick={onAdd}           // 直接传函数引用
onClick={() => onAdd()}   // 或者在箭头函数里显式调用

第三层:引出核心知识点 —— 函数引用与函数执行的区别

这个 bug 本质上是混淆了函数引用函数执行

  • onAdd // 函数引用 —— 拿到函数本身,不执行
  • onAdd() // 函数执行 —— 立即调用,拿到返回值

在 React 中这个区别非常关键:

写法结果
onClick={onAdd}✅ 传引用,点击时 React 调用它
onClick={() => onAdd()}✅ 传箭头函数,点击时箭头函数内部调用它
onClick={onAdd()}❌ 渲染时立即执行,点击时反而不触发
onClick={() => onAdd}❌ 点击时只返回引用,不调用

四种写法,两对两错,错法不同但根因一样:没分清什么时候是传递函数,什么时候是执行函数


第四层:追溯本质 —— 为什么会有这个区分

之所以存在“引用”和“执行”的区分,是因为 JavaScript 中函数是一等公民

函数和数字、字符串一样,可以:

  • 赋值给变量
  • 作为参数传递
  • 作为返回值
  • 存入数组或对象
// 数字可以传递,函数也可以
const a = 42
const b = onAdd    // 把函数当值,赋给变量

// 所以才需要用 () 来区分:你是要“这个值本身”还是要“执行它的结果”
a       // 42
b       // 函数对象
b()     // 执行函数,拿到结果

在 Java、C 这类语言中函数不是一等公民,不能直接传递,也就不会踩这个坑。正是因为 JavaScript 赋予了函数这种灵活性,才需要开发者时刻清楚自己写的是传递还是调用


总结

一个按钮点不动 → 发现少写了 () → 理解函数引用和函数执行的区别 → 追溯到 JavaScript 函数是一等公民这个语言特性。

这个坑教会我的是:遇到“代码没报错但不生效”的问题,先检查函数到底有没有被调用,而不是去排查业务逻辑。看起来最简单的语法问题,背后往往是对语言特性的理解不够深入。