发布于 2026-01-06 0 阅读
0

也许可以给我打电话?面向初学者的回调 DEV 全球展示挑战赛,由 Mux 呈现:推介你的项目!

或许可以给我打电话?给新手的回调技巧

由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!

 
在 JavaScript 中,函数被称为“一等公民”。这意味着它们可以存储在变量中,作为参数传递给其他函数,也可以从其他函数返回。回调函数充分利用了这一特性,因为它本身就是一个作为参数传递给另一个函数并在该函数中被调用的函数。
 


只是一个函数

让我们来看一下这段简单的控制台日志代码片段。

console.log("Hello There"); // Hello There
console.log("I am a tomato!"); // I am a tomato!

这很简单。上面的代码会像你预期的那样逐行执行。我们稍微改动一下。因为我们总是希望在“Hello There”之后输出“I am a tomato!”,所以我们来自动化这个过程,这样当打印“Hello There”时,默认情况下也会打印“I am a tomato!”。第一步是将每个字符串分别封装在各自的函数中。

function greet() {
  console.log("Hello There");
}

function introduce() {
  console.log("I am a tomato!");
}

现在我们将把 `introduce` 函数作为回调函数传递给 `greet` 函数,并在 `greet` 函数内部调用它。请确保只在传递函数定义时不带括号 `()`,如果在传递函数时加上括号 `()`,`introduce` 函数就会立即被调用,而不会等待在 `greet` 函数内部执行。

function greet(callback) {
  console.log("Hello There"); // Hello There!
  callback(); // I am a tomato!
}

function introduce() {
  console.log("I am a tomato!");
}

greet(introduce);

按照惯例,作为参数的回调函数直接称为“callback”,通常你会看到缩写为“cb”。

当我们在执行回调函数的函数内部添加参数时,回调函数的功能会更加强大。让我们通过赋予“introduce”函数更改其名称的能力,使其成为动态函数。

function greet(callback) {
  console.log("Hello There"); // Hello There!
  callback("cucumber"); // I am a cucumber!
}

// Remember, it's possible to store a function inside a variable
var introduce = function(name = "tomato") {
  console.log(`I am a ${name}!`);
}

greet(introduce);

 


可重复使用性

回调函数非常方便,因为它们只是 JavaScript 函数,所以可以很好地重复使用。我们将添加一个名为“callPhone”的函数,然后依次运行原来的“greet”函数和“callPhone”函数。

function greet(callback) {
  console.log("Hello There"); // Hello There!
  callback("cucumber"); // I am a cucumber!
}

function callPhone(callback) {
  console.log("Hello"); // Hello!
  callback(); // I am a tomato!
}

var introduce = function(name = "tomato") {
  console.log(`I am a ${name}!`);
}

greet(introduce);
callPhone(introduce);

 


活动

回调函数在事件监听器中必不可少。我们来看另一个场景。我们想先显示“Hello World”,然后在用户点击按钮后,立即在控制台上显示“I am a tomato!”。我们该如何实现呢?

我们需要使用该addEventListner方法并将其添加到按钮的 DOM(HTML 元素)中。该方法addEventListener接受两个参数。第一个参数是我们要监听的事件类型,第二个参数是指定事件触发后要执行的回调函数。

<button id="button">Who am I?</button>
const button = document.getElementById("button");
function introduce() {
  console.log("I am a tomato!");
}

button.addEventListener("click", introduce); // I am a tomato!

或者,您也可以直接插入一个匿名函数作为回调函数。

const button = document.getElementById("button");

button.addEventListener("click", function() {
  console.log("I am a tomato!");
}); // I am a tomato!

addEventListener这是一个特殊方法,它会自动为我们调用回调操作。
 


网络请求

当我们向 API 发出 AJAX HTTP 网络请求(也称为异步操作)时,请求需要一些时间才能完成并返回响应。为了获取响应数据,需要使用回调函数。一种常见的实现方式是使用 jQuery 的回调get函数。API 服务器会执行回调函数,并将响应数据(通常包含状态信息)返回给回调函数,以告知我们请求是否成功。

// Grabs an filler array of objects 
const url = "https://jsonplaceholder.typicode.com/posts"; 

$.get(url, function(data, status) {
  console.log(data);
})

并非所有 API 都使用回调函数来补充数据,它们也可以使用 Promise,从而实现函数链式调用来处理响应。这超出了本文的讨论范围,因此不会在此赘述。
 


高阶函数

ES6 高阶函数的新特性也利用了回调函数。这些内置的数组方法会根据回调函数传递的逻辑生成一个新的数组。这类方法包括 forEach、map、filter、reduce 等。它们会接收一个回调函数,并向其提供当前值、索引和整个数组。

const numbers = [1,2,3];

numbers.forEach((number, index, array) => {
  console.log(number); // 1, 2, 3
  console.log(index); // 0, 1, 2
  console.log(array); // [1,2,3], [1,2,3], [1,2,3]
})

 


回调地狱

回调函数的一个缺点是它可能会嵌套过深,导致代码难以阅读和维护。这种情况被称为“回调地狱”。我们将以第一个例子为例,并添加更多逻辑。

function greet(distractMe, introduce) {
  console.log("Hello There"); // Hello There!
  distractMe(name => {
    introduce(name, hangUp => {
      console.log("Good Bye")
    })
  });
}

function distractMe(callback) {
  console.log("I am distracting you!!!");
  callback("cucumber");
}

var introduce = function(name = "tomato", callback) {
  console.log(`I am a ${name}!`);
  callback();
}

greet(distractMe, introduce); // =>
// Hello There
// I am distracting you!!!
// I am a cucumber!
// Good Bye

说实话,只用几个花括号和圆括号的 greet 函数示例并不算太糟糕,但想象一下,如果它更复杂,函数之间开始相互依赖,那会是什么样子呢!
 


概括

感谢阅读!回调函数是 JavaScript 的重要组成部分,因为它用途广泛:

  • 活动
  • 可重复使用性
  • 异步性
  • 高阶函数。

 

文章来源:https://dev.to/shimphillip/call-me-maybe-callbacks-for-beginners-k60