Javascript函数作为另一个函数的参数?

Ale*_*lex 11 javascript

我这些天学习了很多javascript,其中一个我不太了解的事情就是将函数作为参数传递给其他函数.我得到了做这些事情的概念,但我自己无法想出任何理想的情况.

我的问题是:

你想什么时候让你的javascript函数作为参数使用另一个函数?为什么不直接为该函数的返回值赋一个变量,并将该变量传递给函数,如下所示:

// Why not do this
var foo = doStuff(params);
callerFunction(foo);

//instead of this
callerFunction(doStuff);
Run Code Online (Sandbox Code Playgroud)

我很困惑为什么我会选择做第二个例子中的事情.

你为什么要这样做?有哪些用例?

谢谢!!

Ori*_*rds 25

有几个用例:

1."包装"功能.

假设你有很多不同的代码.在每一段代码之前和之后,您都想做其他事情(例如:log或try/catch异常).

你可以编写一个"Wrapper"函数来处理这个问题.例如:

function putYourHeadInTheSand(otherFunc) {
    try{
         otherFunc();
    } catch(e) { } // ignore the error
}

....

putYourHeadInTheSand(function(){
    // do something here
});
putYourHeadInTheSand(function(){
    // do something else
});
Run Code Online (Sandbox Code Playgroud)

2.回调.

让我们说你以某种方式加载一些数据.您可以在后台加载它,而不是锁定等待它加载的系统,并在结果到达时对结果执行某些操作.

现在你怎么知道什么时候到来?您可以使用类似信号或互斥的东西,这很难编写和丑陋,或者您可以只做一个回调函数.您可以将此回调传递给Loader函数,该函数可以在完成后调用它.

每次你这样做XmlHttpRequest,这都是正在发生的事情.这是一个例子.

function loadStuff(callback) {
    // Go off and make an XHR or a web worker or somehow generate some data
    var data = ...;
    callback(data);
}

loadStuff(function(data){
    alert('Now we have the data');
});
Run Code Online (Sandbox Code Playgroud)

3.发生器/迭代器

这类似于回调,但不是只调用一次回调,而是可以多次调用它.想象一下,您的加载数据功能不只是加载一位数据,也许加载200.

这最终与for/foreach循环非常相似,除了它是异步的.(您不等待数据,它在准备就绪时会调用您).

function forEachData(callback) {
    // generate some data in the background with an XHR or web worker
    callback(data1);
    // generate some more data in the background with an XHR or web worker
    callback(data2);
    //... etc
}

forEachData(function(data){
    alert('Now we have the data'); // this will happen 2 times with different data each time
});
Run Code Online (Sandbox Code Playgroud)

4.懒加载

让我们说你的函数用一些文本做了些什么.但它只需要文本中的一次可能是5次,并且加载文本可能非常昂贵.

所以代码看起来像这样

var text = "dsakjlfdsafds"; // imagine we had to calculate lots of expensive things to get this.
var result = processingFunction(text);
Run Code Online (Sandbox Code Playgroud)

处理功能实际上只需要文本的20%!我们浪费了所有这些额外时间加载它的努力.

您可以传递一个生成文本的函数,而不是传递文本,如下所示:

var textLoader = function(){ return "dsakjlfdsafds"; }// imagine we had to calculate lots of expensive things to get this.
var result = processingFunction(textLoader);
Run Code Online (Sandbox Code Playgroud)

你必须改变你processingFunction的期望另一个功能而不是文本,但这真的很小.现在发生的事情是,processingFunction只会调用textLoader它需要的20%的时间.其他80%的时间,它不会调用该功能,你不会浪费所有的努力.

4A.高速缓存

如果你发生了延迟加载,那么该textLoader函数可以在结果文本获得后私下将结果文本存储在变量中.有人第二次调用它textLoader,它可以返回该变量并避免昂贵的计算工作.

调用的代码textLoader不知道或不关心数据是否被缓存,它透明地更快.

通过传递函数可以做很多更高级的事情,这只是表面上的问题,但希望它指出你正确的方向:-)


Jon*_*cto 7

最常见的用法之一是作为回调.例如,使用一个函数对数组中的每个项运行一个函数,并将结果重新分配给数组项.这要求函数为每个项调用用户的函数,除非传递函数,否则这是不可能的.

这是这样一个函数的代码:

function map(arr, func) {
    for (var i = 0; i < arr.length; ++i) {
        arr[i] = func(arr[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法的一个例子是将数组中的每个项乘以2:

var numbers = [1, 2, 3, 4, 5];
map(numbers, function(v) {
    return v * 2;
});

// numbers now contains 2, 4, 6, 8, 10
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 6

如果callerFunctiondoStuff稍后打电话,或者想要多次打电话,你会这样做.

这种用法的典型示例是回调函数,您将回调函数传递给函数jQuery.ajax,然后在完成某些操作时调用您的回调(例如AJAX请求)

编辑:回答你的评论:

function callFiveTimes(func) {
    for(var i = 0; i < 5; i++) {
        func(i);
    }
}

callFiveTimes(alert);  //Alerts numbers 0 through 4
Run Code Online (Sandbox Code Playgroud)