面试官:你在项目研发时,踩过什么坑?
第一层:问题现象
在做软件分发管理系统时,有一个“新增”按钮,点击后应该弹出弹窗,但点了没有任何反应。
代码是这样写的:
<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 函数是一等公民这个语言特性。
这个坑教会我的是:遇到“代码没报错但不生效”的问题,先检查函数到底有没有被调用,而不是去排查业务逻辑。看起来最简单的语法问题,背后往往是对语言特性的理解不够深入。