本文深入解析JavaScript中回调函数的核心概念,解释函数作为一等公民的特性。通过具体代码示例演示如何将匿名函数作为参数传递并在父函数中执行,结合Express框架中的app.use实例,阐明回调机制在Node.js开发中的实际应用与执行流程。
回调函数在Express中的应用
近期研究Express框架时,随处可见以函数作为参数的回调函数用法。若无法理解这一概念,阅读Node.js和Express代码时将困难重重。例如以下代码片段:
代码如下:
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});上述代码中,app是一个对象,use是其方法,而方法的参数是一个带有参数的匿名函数,函数体直接写在后面。如何理解这段代码?我们需要先掌握回调函数的基本概念。
JavaScript中函数的对象特性
首先需要明确,在JavaScript中,函数也是一种对象,它可以被赋值给变量,也可以作为参数传递给其他函数。例如:
代码如下:
var doSomething = function(a,b)
{
return a + b;
}这段代码定义了一个匿名函数,除了没有名称外,它与普通函数无异。随后将该匿名函数赋值给变量doSomething。接下来进行调用:
代码如下:
console.log(doSomething(2,3));
执行后将输出5。
回调函数的执行流程解析
回调函数是指放置在另一个函数(如parent)的参数列表中,作为参数传递给该parent,并在parent函数体的特定位置执行。这听起来可能有些抽象,请看下面的例子:
代码如下:
// To illustrate the concept of callback
var doit = function(callback)
{
var a = 1,
b = 2,
c = 3;
var t = callback(a,b,c);
return t + 10;
};
var d = doit(function(x,y,z){
return (x+y+z);
});
console.log(d);首先定义doit函数,它接收一个参数callback。这里的callback即为回调函数,名称可以任意指定。查看函数体,先定义变量a、b、c,然后调用callback函数,最后返回一个值。
接下来调用doit函数。需要注意的是,在定义doit时,callback并未具体定义,因此当时并不清楚callback的具体作用。这很合理,正如平时定义函数时,参数仅给出名称(如a),在函数体内使用a,但整个过程并不知晓a的具体含义,只有在调用该函数时才指定a的具体值(如2)。回到doit的调用,我们需要指定callback具体是什么。可以看到,此处的函数实现了求和(sum)功能。
上述代码的执行过程如下:
调用doit函数,参数为一个匿名函数;进入doit的函数体,先定义a、b、c,然后执行之前的匿名函数,传入a、b、c作为参数,并返回t,最后将t+10的值赋给d。
理解回调机制的实际意义
回到最初的例子,app.use(...)是一个函数调用。我们可以推断,之前一定定义了一个use方法,只是此处未展示。对比这两个例子,即可迅速理解回调机制。
在使用Node.js和Express时,不可能每个方法或函数都去查找其定义。因此,只需知道定义中向callback传递了哪些参数即可。在调用方法或函数时,我们在参数中自定义匿名函数以完成特定功能。
Over!