JavaScript 回调函数怎么写
你有没有遇到过这种情况:想让外卖员“先取餐、再送上门、最后让我签收”,结果对方却把餐品和快递混在一起送来了?在编程里,这种“按顺序做几件事”的需求,就需要一种叫回调函数的东西来实现,它就像你给外卖员留的“操作步骤清单”,能明确告诉程序“做完A,再做B,最后做C”。
很多人刚接触JavaScript时,会觉得回调函数是“有点绕的写法”,其实它本质上就是把一段代码当“参数”传给另一段代码,等特定时机再执行。咱们用生活化的例子拆解,新手也能很快上手。

先搞懂最基础的回调写法
咱们拿“买奶茶”打比方:你先下单(点奶茶),等店员做好(取餐),再付钱。在JavaScript里,“付钱”的动作要等“做好奶茶”之后执行,这时候就可以用回调函数实现。
基础写法很简单,先写一个“做奶茶”的函数,再把“付钱”这段代码作为参数传进去:
`javascript
// 做奶茶的函数,最后一个参数就是回调函数
function makeMilkTea(milkTeaName, callback) {
console.log(正在做${milkTeaName}...);
// 模拟等奶茶做好的1秒延迟
setTimeout(() => {
console.log(${milkTeaName}做好啦);
// 奶茶做好后,执行传进来的回调函数
callback();
}, 1000);
}
// 调用函数,把“付钱”当回调传进去
makeMilkTea('珍珠奶茶', function() {
console.log('付奶茶钱啦');
});
`
运行这段代码,控制台会依次打印:“正在做珍珠奶茶...”→“珍珠奶茶做好啦”→“付奶茶钱啦”,完全符合你要的顺序。这里的function() { console.log('付奶茶钱啦'); }就是回调函数,它会在“奶茶做好”这个时机被触发。
带参数的回调,怎么传值?
有时候回调需要用到前面步骤的结果,比如奶茶做好后,不仅要付钱,还要“拿到奶茶喝”,这时候就得把“做好的奶茶”传给回调。
还是用买奶茶的例子,把回调改成带参数的形式,让它能接收“奶茶结果”:
`javascript
function makeMilkTea(milkTeaName, callback) {
console.log(正在做${milkTeaName}...);
setTimeout(() => {
const finishedTea = milkTeaName; // 做好的奶茶
// 把做好的奶茶传给回调
callback(finishedTea);
}, 1000);
}
// 调用时,用参数接收回调传过来的奶茶
makeMilkTea('珍珠奶茶', function(tea) {
console.log(拿到${tea},喝奶茶啦);
});
`
现在运行代码,打印结果会变成:“正在做珍珠奶茶...”→“珍珠奶茶做好啦”→“拿到珍珠奶茶,喝奶茶啦”。这里的tea就是回调接收的、前面步骤的输出值,相当于你拿到了刚做好的奶茶。
避免“回调地狱”的小提示
如果要做“下单→取奶茶→加配料→打包→付钱”一连串的步骤,有人会把回调一层套一层,就像“俄罗斯套娃”:
`javascript
// 不推荐的嵌套写法
makeMilkTea('珍珠奶茶', function(tea) {
addTopping(tea, '珍珠', function(teaWithTopping) {
packTea(teaWithTopping, function(packedTea) {
pay(packedTea, function() {
console.log('全部完成');
});
});
});
});
`
这种写法会让代码难读、难改,这就是大家说的“回调地狱”。实际开发中,你可以把每一步的回调单独拆成函数,或者用更现代的Promise、async/await语法替代,就像把套娃拆开,让代码更清爽。
回调函数的核心就是“把要等时机执行的代码,提前当参数传进去”,用生活里的“按步骤做事”类比,就能轻松理解。掌握了基础写法,再慢慢练习拆分回调,就能写出清晰又好用的代码了。