JS:callback回调函数

函数可以像“变量”一样传递

在 JavaScript 里:函数也是一种数据。所以函数可以:

  • 赋值给变量
  • 作为参数传递
  • 作为返回值
function hello() {
  console.log("hello");
}

let fn = hello;

fn(); // 输出:hello
/*
hello → 函数
fn → 指向这个函数
*/

什么是 callback(回调函数)

callback 就是 作为参数传给另一个函数的函数,并在之后被调用。

  • 函数 A 把函数 B 当作参数
  • 函数 A 在某个时刻执行函数 B
function greet(name, callback) { // 名字不唯一,如果callback改成ABC
  console.log("Hello " + name);
  callback(); // 这里也要改成ABC
}

function sayBye() {
  console.log("Bye!");
}

greet("Tom", sayBye);

执行过程:

调用 greet("Tom", sayBye)

greet 内部:
1 打印 Hello Tom
2 执行 callback()

callback 指向 sayBye

于是执行 sayBye()

callback 与异步回调

JavaScript 中,回调函数(callback)实际上是用来 处理异步操作 的。当你需要等待一些 异步事件(如网络请求、定时器、文件读取等)时,把需要等待的代码放进回调函数里,就能保证这些操作不会阻塞主线程的执行。

// 模拟网络请求
function fetchData(callback) {
  console.log("请求开始");
  
  setTimeout(() => {
    console.log("数据返回");
    callback("数据");
  }, 2000);  // 假设 2 秒后返回数据
}

console.log("请求之前");
fetchData((data) => {
  // 这段代码是需要等网络请求结束后再执行的代码
  // 如果主线程不愿意等待,就放在异步回调函数里面
  console.log("接收到数据:", data);
});
console.log("请求之后");

/*
输出:
  请求之前
  请求开始
  请求之后
  数据返回
  接收到数据: 数据
*/

回调作为对象属性

事件监听:UI 交互

在前端开发中,回调函数作为对象的属性最常见的用途就是 事件监听,例如监听按钮点击、表单提交、输入框变化等。

const button = {
  onClick: null, // 事件回调初始化为空

  // 按钮点击事件处理
  click() {
    console.log("按钮被点击了!");

    if (this.onClick) {
      this.onClick(); // 执行回调函数
    }
  }
};

// 注册点击事件回调
button.onClick = () => {
  console.log("按钮点击事件已处理!");
};

// 触发点击事件
button.click();

这里,onClick 是按钮对象的 回调属性,我们把回调函数赋值给 onClick,当 click 方法触发时执行该回调。

典型用途:

  • 按钮点击
  • 用户输入(如表单、输入框变化)
  • 窗口大小变化
  • 页面滚动等

异步操作回调(例如,网络请求)

在异步编程中,回调作为对象属性也非常常见,通常用来处理 异步操作的结果

const dataLoader = {
  onDataLoaded: null, // 数据加载完成的回调

  // 模拟加载数据
  loadData() {
    setTimeout(() => {
      console.log("数据加载完成!");
      
      // 执行回调
      if (this.onDataLoaded) {
        this.onDataLoaded("加载的数据");
      }
    }, 2000);
  }
};

// 注册数据加载完成的回调
dataLoader.onDataLoaded = (data) => {
  console.log("接收到的数据:", data);
};

// 调用 loadData,模拟数据加载
dataLoader.loadData();

在这个例子中,onDataLoaded 是回调函数,它作为 dataLoader 对象的属性。loadData 方法模拟一个异步操作(通过 setTimeout),并在数据加载完成后调用回调。

典型用途:

  • 网络请求完成后的回调(例如 AJAX 请求)
  • 定时器到期后的回调(例如 setTimeoutsetInterval
  • 文件读取完成后的回调

自定义事件系统

回调作为对象的属性也可以用来实现 自定义事件系统。在这种情况下,回调函数用来处理 自定义的事件

class EventEmitter {
  constructor() {
    this.events = {}; // 存储事件名与回调函数
  }

  // 订阅事件
  on(event, callback) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }

  // 触发事件
  emit(event, data) {
    if (this.events[event]) {
      this.events[event].forEach(callback => callback(data));
    }
  }
}

const emitter = new EventEmitter();

// 订阅事件
emitter.on('dataReceived', (data) => {
  console.log("数据接收成功:", data);
});

// 触发事件
emitter.emit('dataReceived', { id: 1, name: 'Tom' });

这里,我们创建了一个 EventEmitter 类,允许注册回调函数(通过 on 方法)并触发事件(通过 emit 方法)。回调函数在 emit 时触发,处理特定事件的数据。

典型用途:

  • 自定义事件系统(例如,Node.js 的 EventEmitter 类)
  • 发布/订阅模式
  • 组件间通信

在方法里面使用回调函数

异步操作处理

在处理异步操作时(比如等待网络请求、定时器等),我们会把回调函数作为参数传入,并在异步操作完成后执行回调。

function fetchData(callback) {
  setTimeout(() => {
    const data = { user: "Tom", age: 25 };
    
    // 异步任务完成后执行回调
    callback(data);
  }, 2000);
}

fetchData((data) => {
  console.log("接收到数据:", data);
});

在这个例子中,fetchData 方法通过 setTimeout 模拟了一个异步操作,等操作完成后,通过回调函数传递数据并执行回调逻辑。

这种方式的常见用途:

  • 网络请求(如 fetchaxios 等)
  • 处理异步任务(如文件读取、图片加载等)
  • 定时器处理(如 setTimeoutsetInterval

数组处理

JavaScript 数组方法(如 forEachmapfilter)都广泛使用回调函数来 定制每个元素的处理。这是在方法内部使用回调的一个典型例子。

const numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
  console.log(num * 2);  // 每个数字乘以 2
});

forEach 中,传入的回调函数会被 依次应用到数组的每个元素

这种方式的常见用途:

  • 数组遍历
  • 数组过滤(filter
  • 数组映射(map

自定义逻辑操作

方法内的回调函数可以让你 动态定制方法的行为,这非常常见,尤其在你希望某个方法的执行逻辑有很强的 可扩展性灵活性 时。

function processData(data, callback) {
  const result = data.map((item) => item * 2);
  
  // 执行回调,传递处理后的数据
  callback(result);
}

processData([1, 2, 3], (result) => {
  console.log("处理后的数据:", result);
});

在这个例子中,processData 接收一个回调函数 callback,它在处理完数据后调用回调并传递处理结果。你可以通过传递不同的回调来执行不同的操作。

这种方式的常见用途:

  • 数据处理(如格式转换、聚合操作等)
  • 任务调度(如对多个任务的顺序或并发控制)

×

喜欢就点赞,疼爱就打赏