如何用简单的英语解释回调?它们与从一个函数调用另一个函数从调用函数获取上下文有什么不同?如何向新手程序员解释它们的强大功能?
当前回答
如果没有回调或其他特殊的编程资源(如线程等),程序就是一个指令序列,一个接一个地按顺序执行,即使具有某种由某些条件决定的“动态行为”,所有可能的场景都必须预先编程。
因此,如果我们需要为程序提供一个真正的动态行为,我们可以使用回调。通过回调,你可以通过参数指令,一个程序调用另一个程序,提供一些先前定义的参数,并可以期望一些结果(这是契约或操作签名),因此这些结果可以由之前不知道的第三方程序产生/处理。
这种技术是应用于计算机运行的程序、函数、对象和所有其他类型代码的多态的基础。
以回调为例的人类世界很好地解释了当你在做一些工作时,假设你是一个画家(这里你是主程序,负责绘画),有时会打电话给你的客户,请他批准你的工作结果,所以,他决定图片是否好(你的客户是第三方程序)。
在上面的例子中,你是一个画家,并“委托”给其他人的工作来批准结果,图片是参数,每个新的客户端(回调的“函数”)改变你的工作结果,决定他想要的图片(客户端做出的决定是“回调函数”返回的结果)。
我希望这个解释对你有用。
其他回答
假设你需要一个函数返回10的平方,那么你写一个函数:
function tenSquared() {return 10*10;}
之后你需要9的平方,所以你写了另一个函数:
function nineSquared() {return 9*9;}
最终你将用一个泛型函数替换所有这些:
function square(x) {return x*x;}
同样的想法也适用于回调。你有一个函数,它做一些事情,当完成时调用doA:
function computeA(){
...
doA(result);
}
之后你想要完全相同的函数调用doB,而不是你可以复制整个函数:
function computeB(){
...
doB(result);
}
或者你可以将回调函数作为变量传递,并且只需要使用该函数一次:
function compute(callback){
...
callback(result);
}
然后你只需要调用compute(doA)和compute(doB)。
除了简化代码之外,它还让异步代码通过在完成时调用任意函数来让您知道它已经完成,这与打电话给某人并留下回调号码类似。
什么是回调函数?
对第一个问题的简单回答是,回调函数是通过函数指针调用的函数。如果你将一个函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用它所指向的函数时,就被称为回调。
回调函数很难跟踪,但有时它非常有用。尤其是在设计库的时候。回调函数就像让你的用户给你一个函数名,你会在一定条件下调用这个函数。
例如,您编写了一个回调计时器。它允许您指定持续时间和调用什么函数,函数将相应地被回调。“每10秒运行myfunction() 5次”
或者,您可以创建一个函数目录,传递一个函数名列表,并要求库进行相应的回调。"如果成功,回调成功(),如果失败,回调失败()。"
让我们看一个简单的函数指针的例子
void cbfunc()
{
printf("called");
}
int main ()
{
/* function pointer */
void (*callback)(void);
/* point to your callback function */
callback=(void *)cbfunc;
/* perform callback */
callback();
return 0;
}
如何传递参数回调函数?
注意到实现回调的函数指针接受void *,这表明它可以接受任何类型的变量,包括结构。因此,您可以通过结构传递多个参数。
typedef struct myst
{
int a;
char b[10];
}myst;
void cbfunc(myst *mt)
{
fprintf(stdout,"called %d %s.",mt->a,mt->b);
}
int main()
{
/* func pointer */
void (*callback)(void *); //param
myst m;
m.a=10;
strcpy(m.b,"123");
callback = (void*)cbfunc; /* point to callback function */
callback(&m); /* perform callback and pass in the param */
return 0;
}
回调允许您将自己的代码插入到另一个代码块中,以便在另一个时间执行,从而修改或添加其他代码块的行为以满足您的需要。您获得了灵活性和可定制性,同时能够拥有更可维护的代码。
更少的硬代码=更容易维护和更改=更少的时间=更多的业务价值=很棒。
例如,在javascript中,使用Underscore.js,你可以在这样的数组中找到所有偶数元素:
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
示例由Underscore.js提供:http://documentcloud.github.com/underscore/#filter
说白了,回调就是承诺。乔、简、大卫和萨曼莎拼车去上班。乔今天开车。简,大卫和萨曼莎有几个选择:
每五分钟查看一下窗户,看看乔是否出去了 继续做他们的事,直到乔按门铃。
选项1:这更像是一个轮询示例,Jane将被困在一个“循环”中,检查Joe是否在室外。在此期间简不能做其他事情。
选项2:这是回调示例。简告诉乔当他在外面时按她的门铃。她给了他一个按门铃的“功能”。Joe不需要知道门铃是如何工作的,也不需要知道它在哪里,他只需要调用那个函数,即当他在那里时按门铃。
回调是由“事件”驱动的。在这个例子中,“事件”是乔的到来。例如,在Ajax中,事件可以是异步请求的“成功”或“失败”,并且每个事件都可以有相同或不同的回调。
In terms of JavaScript applications and callbacks. We also need to understand "closures" and application context. What "this" refers to can easily confuse JavaScript developers. In this example within each person's "ring_the_door_bell()" method/callback there might be some other methods that each person need to do based on their morning routine ex. "turn_off_the_tv()". We would want "this" to refer to the "Jane" object or the "David" object so that each can setup whatever else they need done before Joe picks them up. This is where setting up the callback with Joe requires parodying the method so that "this" refers to the right object.
希望有帮助!
回调函数:
我们定义了一个名为callback的回调函数,给它一个参数otherFunction,并在函数体中调用它。
function callback(otherFunction){
otherFunction();
}
当我们调用回调函数时,它需要一个类型为函数的参数,因此我们使用匿名函数调用它。但是,如果实参不是function类型,则会产生错误。
callback(function(){console.log('SUCCESS!')});
callback(1); // error
烤披萨的例子。 烤炉 披萨底,上面有配料 这里,烤箱是回调函数。 披萨的配料是另一个功能。
值得注意的是,不同的披萨原料可以做出不同类型的披萨,但烘焙披萨的烤箱是一样的。 这在某种程度上是回调函数的工作,它不断期望具有不同功能的函数,以产生不同的自定义结果。