回调作为参数
回调很有用,因为它们允许您使用以下命令“配置”函数code.
典型的例子是一个排序函数,它允许您指定自己的排序标准。我将使用一个函数,该函数根据某些条件返回数组的最小值,因为它比排序更简单,但它仍然可以很好地作为说明:
function min(collection, property) {
if (collection.length == 0) {
return null;
}
var minIndex = 0;
var minValue = collection[0][property];
for (var i = 1; i < collection.length; ++i) {
if (minValue > collection[i][property]) {
minValue = collection[i][property];
minIndex = i;
}
}
return collection[minIndex];
}
var items = [
{ name: "John", age: 20 }, { name: "Mary", age: 18 }
];
alert(min(items, 'age').name); // prints "Mary"
看到这段代码运行. 它有什么问题呢?
问题是,虽然我们做了一些努力来创建一个可配置的min
函数(它根据我们指定的任何属性找到最小值),但从一般意义上来说它仍然相当有限,因为它只能根据一个单一属性找到最小值.
如果我们的数据是这样的怎么办?
var items = [ "John/20", "Mary/18" ];
这不再是一个对象数组,而是一个格式化字符串数组。它具有与原始集合相同的数据,但结构不同。结果,原来的min
不能使用函数来处理它。
现在我们可以编写另一个版本min
它适用于字符串而不是对象,但这有点毫无意义(有无数种方法可以表示相同的数据)。对于一种特定情况,这可能是一种快速但肮脏的解决方案,但是考虑图书馆作家的问题:如果不知道每种情况下数据的结构如何,他们如何编写一个对每个人都有用的函数?
回调来救援
简单:制作min
通过允许用户指定功能更强大如何从数据中提取标准。这听起来很像“给出函数代码以从数据中提取标准”,这正是我们要做的。min
将接受一个callback:
function min(collection, callback) {
if (collection.length == 0) {
return null;
}
var minIndex = 0;
var minValue = callback(collection[0]);
for (var i = 1; i < collection.length; ++i) {
if (minValue > callback(collection[i])) {
minValue = callback(collection[i]);
minIndex = i;
}
}
return collection[minIndex];
}
var items = [ "John/20", "Mary/18" ];
var minItem = min(items, function(item) {
return item.split('/')[1]; // get the "age" part
});
alert(minItem);
看到这段代码运行.
现在我们的代码终于可以重用了。我们可以轻松地将其配置为与第一个一起使用and第二种类型的数据只需最少的努力。
查看支持回调的函数处理两种类型的数据。这是我们获得极大灵活性的结果,因为允许用户以回调的形式提供代码作为我们函数的一部分运行。
异步编程中的回调
回调的另一个主要用途是启用异步编程模型。这在您计划完成操作但不希望程序在操作完成之前停止运行的所有情况下都很有用。
为了使其工作,您为该操作提供回调函数并有效地告诉它:去帮我做这个工作,完成后给我回电话。然后,您可以自由地继续做任何您喜欢的事情,因为您知道当结果可用时您指定的函数将运行。
这在使用 AJAX 的 Web 中最为明显:您向 Web 服务器发出请求,然后当收到回复时你以某种方式对其采取行动。您不想当场等待响应,因为这可能需要很长时间(例如,如果存在连接问题),并且您不希望您的程序一直没有响应。
有关 AJAX 回调的示例,请参阅 jQuery 的文档load功能。