Function 如何用简单的英语解释回调?它们与从一个函数调用另一个函数有何不同?

Function 如何用简单的英语解释回调?它们与从一个函数调用另一个函数有何不同?,function,callback,language-agnostic,terminology,Function,Callback,Language Agnostic,Terminology,如何用简单的英语解释回调?从一个函数调用另一个函数与从调用函数获取上下文有什么不同?如何向新手程序员解释它们的能力 通常我们向函数发送变量。 假设您有一个任务,在该任务中,变量在作为参数提供之前需要进行处理—您可以使用回调 function1(var1,var2)是常用的方法 如果我想处理var2,然后作为参数发送,该怎么办? function1(var1,function2(var2)) 这是一种回调类型,其中function2执行一些代码并将变量返回初始函数 最好从一个例子开始:) 假设有两

如何用简单的英语解释回调?从一个函数调用另一个函数与从调用函数获取上下文有什么不同?如何向新手程序员解释它们的能力

通常我们向函数发送变量。 假设您有一个任务,在该任务中,变量在作为参数提供之前需要进行处理—您可以使用回调

function1(var1,var2)
是常用的方法

如果我想处理
var2
,然后作为参数发送,该怎么办?
function1(var1,function2(var2))


这是一种回调类型,其中
function2
执行一些代码并将变量返回初始函数

最好从一个例子开始:)

假设有两个模块A和B

当模块B中发生某些事件/情况时,您希望通知模块A。。但是,模块B不知道您的模块A。它所知道的只是通过模块A提供给它的函数指针指向(模块A的)特定函数的地址

因此,B现在所要做的就是,当使用函数指针发生特定事件/条件时,将其“回调”到模块A中。A可以在回调函数中执行进一步的处理

function processArray(arr, callback) {
    var resultArr = new Array(); 
    for (var i = arr.length-1; i >= 0; i--)
        resultArr[i] = callback(arr[i]);
    return resultArr;
}

var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]

*)这里的一个明显优势是,您将模块A的所有内容从模块B中抽象出来。模块B不必关心模块A是谁/什么。

[编辑]当我们有两个函数时,比如function和functionB,如果function取决于functionB

然后我们将函数b称为a。这在Spring框架中被广泛使用


应用程序通常需要根据其上下文/状态执行不同的功能。为此,我们使用一个变量来存储有关要调用的函数的信息。‪根据需要,应用程序将使用有关要调用的函数的信息设置此变量,并使用相同的变量调用函数

在javascript中,示例如下所示。在这里,我们使用方法参数作为变量,在其中存储有关函数的信息

function processArray(arr, callback) {
    var resultArr = new Array(); 
    for (var i = arr.length-1; i >= 0; i--)
        resultArr[i] = callback(arr[i]);
    return resultArr;
}

var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]

你觉得不舒服,所以去看医生。他检查你,确定你需要一些药物。他开了一些药,然后把处方打到你当地的药房。你回家吧。稍后你的药房会打电话告诉你你的处方已经准备好了。你去把它捡起来

回调允许您将自己的代码插入另一个代码块,以便在另一时间执行,从而修改或添加该另一个代码块的行为以满足您的需要。您获得了灵活性和可定制性,同时能够拥有更多可维护的代码

更少的硬代码=更易于维护和更改=更少的时间=更多的业务价值=卓越

例如,在javascript中,使用下划线.js,可以在数组中找到所有偶数元素,如下所示:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
my $var = 2;
my $val = someCallerBackFunction(sub callback { return $var * 3; });
# Perlistas note: I know the sub doesn't need a name, this is for illustration
var lottoNumbers = [];
var callback = function(theNames) {
  for (var i=0; i<theNames.length; i++) {
    lottoNumbers.push(theNames[i].length);
  }
};

db.executeQuery("SELECT name " +
                "FROM tblEveryOneInTheWholeWorld " +
                "ORDER BY proximity DESC " +
                "LIMIT 5", callback);

while (lottoNumbers.length < 5) {
  playGolf();
}
playLotto(lottoNumbers);

subline.js提供的示例:

想象一个朋友要离开你的家,你告诉她“回家后给我打电话,让我知道你安全到达”;这(字面上)是一个回电。这就是回调函数的含义,与语言无关。您希望某个过程在完成某项任务后将控制权传递给您,因此您为它提供了一个函数,用于回调您

例如,在Python中

grabDBValue( (lambda x: passValueToGUIWindow(x) ))
grabDBValue
可以编写为仅从数据库中获取一个值,然后让您指定如何实际处理该值,以便它接受一个函数。您不知道何时或是否
grabDBValue
将返回,但如果/何时返回,您知道希望它执行什么操作。这里,我传入一个匿名函数(或lambda),它将值发送到GUI窗口。我可以通过以下操作轻松更改程序的行为:

grabDBValue( (lambda x: passToLogger(x) ))
回调在函数是第一类值的语言中工作得很好,就像通常的整数、字符串、布尔值等。在C中,可以通过传递指向函数的指针来“传递”函数,调用方可以使用它;在Java中,调用方将要求使用特定方法名的特定类型的静态类,因为类之外没有函数(“方法”);在大多数其他动态语言中,只需使用简单的语法传递函数即可

Protip: 在具有词法范围的语言(如Scheme或Perl)中,您可以使用如下技巧:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
my $var = 2;
my $val = someCallerBackFunction(sub callback { return $var * 3; });
# Perlistas note: I know the sub doesn't need a name, this is for illustration
var lottoNumbers = [];
var callback = function(theNames) {
  for (var i=0; i<theNames.length; i++) {
    lottoNumbers.push(theNames[i].length);
  }
};

db.executeQuery("SELECT name " +
                "FROM tblEveryOneInTheWholeWorld " +
                "ORDER BY proximity DESC " +
                "LIMIT 5", callback);

while (lottoNumbers.length < 5) {
  playGolf();
}
playLotto(lottoNumbers);

$val
在这种情况下将是
6
,因为回调可以访问在定义它的词法环境中声明的变量。词法作用域和匿名回调是一个强大的组合,值得新手程序员进一步研究。

假设您需要一个返回10平方的函数,那么您可以编写一个函数:

function tenSquared() {return 10*10;}
function nineSquared() {return 9*9;}
function square(x) {return x*x;}
function computeB(){
    ...
    doB(result);
}
稍后,您需要9的平方,因此您可以编写另一个函数:

function tenSquared() {return 10*10;}
function nineSquared() {return 9*9;}
function square(x) {return x*x;}
function computeB(){
    ...
    doB(result);
}
最终,您将使用通用函数替换所有这些函数:

function tenSquared() {return 10*10;}
function nineSquared() {return 9*9;}
function square(x) {return x*x;}
function computeB(){
    ...
    doB(result);
}
同样的想法也适用于回调。您有一个执行某些操作的函数,完成后调用doA:

function computeA(){
    ...
    doA(result);
}
稍后,您希望完全相同的函数调用doB,您可以复制整个函数:

function tenSquared() {return 10*10;}
function nineSquared() {return 9*9;}
function square(x) {return x*x;}
function computeB(){
    ...
    doB(result);
}
或者,您可以将回调函数作为变量传递,并且只需使用该函数一次:

function compute(callback){
    ...
    callback(result);
}
然后你只需要调用compute(doA)和compute(doB)


除了简化代码之外,它还让异步代码在完成时调用任意函数,让您知道它已经完成,类似于您在电话中呼叫某人并留下回拨号码

隐喻性解释:

我有一个包裹要寄给一个朋友,我也想知道我的朋友什么时候收到它

所以我把包裹拿到邮局,让他们送去。如果我想知道我的朋友何时收到包裹,我有两个选择:

(a) 我可以在邮局等
public interface Callback
{
    public void notify(Result result);
}
public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}
public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}
public interface Events {

public void clickEvent();
public void longClickEvent();
}
package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}
public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}
public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}
public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}
public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}
function main() {
  callVet();
  // blocked for 15 minutes
  walkDog();
  doTaxes();
  doDishes();
  answerPeronalEmails();
  doLaundry();
}
function main() {
  callVet(function vetCallback(vetOnThePhoneReadyToSpeakWithMe) {
    talkToVetAboutTestResults(vetOnThePhoneReadyToSpeakWithMe);
  });
  walkDog();
  doTaxes();
  doDishes();
  answerPeronalEmails();
  doLaundry();
}
function main() {
  displayNavbar();
  const user = getUser();
  // wait a few seconds for response...
  displayUserDashboard(user);
  displaySidebar();
  displayFooter();
}
function main() {
  displayNavbar();
  getUser(function (user) {
    displayUserDashboard(user);
  });
  displaySidebar();
  displayFooter();
}