回调函数

159 阅读3分钟

既然函数与任何可以被赋值给变量的数据是相同的,那么它当然可以像其他数据那样被定义、删除、拷贝,以及当成参数传递给其他函数。

//例子一
function invokeAdd(a,b){
    return a() + b();
};

function one(){
    return 1;
};

function two(){
    return 2;
};

//调用一下
invokeAdd(one,two);    //3

像这样,我们把函数 one 和函数 two 作为参数传递给目标函数 invokeAdd( ),就可以得到执行的结果了。当然,我们也可以直接使用匿名函数(即函数表达式)来替代 one( ) 和 two( ),以作为目标函数的参数:

invokeAdd( function(){return 1;} , function(){return 2;});

//或者换个可读性更好的写法:
invokeAdd(
    function(){
        return 1;
    },
    function(){
        return 2;
    }
);

当我们将函数 A 传递给函数 B,并由 B 来执行 A 时,A 就成为了一个回调函数(callback functions);如果 A 还是一个匿名函数,那么我们就称之为 匿名回调函数。

现在,我们知道了什么是回调函数,接下来我们来继续讨论它的优势:

  • 它可以让我们在不做命名的的情况下传递函数(这意味着可以节省变量名的使用);
  • 我们可以将一个函数调用操作委托给另一个函数(这意味可以节省一些代码编写工作);
  • 它们也有助于提升性能。

那么,应该什么时候使用回调函数呢?下面我们将通过一个案例来示范下回调函数及上面提到的它的几个优势。我们定义了两个函数: 

第一个 multiplyByTwo( ) ,该函数会通过一个循环将其所接受的三个函数分别乘以 2 , 并以数组的形式返回结果; 

第二个函数 addOne( ) 只接受一个值,然后将它加 1 并返回。

function multiplyByTwo(a,b,c){
    var i , ar = [];
    for( i = 0 ; i < 3 ; i++ ){        ar[i] = arguments[i] * 2;
    }
    return ar;
};

function addOne(a){
    return a + 1;  
};

//测试下调用
multiplyByTwo(1,2,3);    //[2,4,6]

addOne(100);    //101

OK,接下来,假设我们有三个元素,我们要实现这三个元素在这两个函数之间的传递,这需要我们定义另一个数组,用于存储第一步的结果:

var myarr = [];
myarr = multiplyByTwo(10,20,30);

然后用循环遍历每个元素,并将它们分别传递给 addOne( ):

for(var i = 0 ; i < 3 ; i++ ){
    myarr[i] = addOne(myarr[i]);};

myarr;    //[21,41,61]

如你所见,这段代码可以工作,但是显然还有一定的改善空间。特别是这里使用了两个循环,如果数据量很大或者循环操作很复杂的话,开销一定不小。

因此,我们需要将它们合二为一。这就需要对 multiplyByTwo( ) 函数做一些改动,使其接受一个回调函数,并在每次迭代操作中调用它:

//改造 multiplyByTwo() 函数
function multiplyByTwo(a,b,c,callback){
    var i , ar = [];
    for( i = 0 ; i < 3 ; i++ ){
        ar[i] = callback( arguments[i] * 2 );
    }
    return ar;
};
myarr = multiplyByTwo(1,2,3,addOne);
myarr;    //[3,5,7]

修改之后,之前的工作只需要一次函数调用就够了,另外,在实践中,我们更多时候会考虑用匿名函数来代替 addOne( ) ,这样做可以节省一个额外的全局变量:

multiplyByTwo(1,2,3,function(a){
    return a + 1;
});    //[3,5,7]

而且,使用匿名函数也更易于随时根据需求调整代码:

multiplyByTwo(1,2,3,function(){
    return a + 2;
});    //[4,6,8]

本文摘自《JavaScript面向对象编程指南》,分享的目的仅供个人学习和理解,如需转载请备注本文出处,谢谢!