什么是回调函数?
被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数
一个回调函数,也被称为高阶函数,是一个被作为参数传递给另一个函数(在这里我们把另一个函数叫做“otherFunction”)的函数,回调函数在otherFunction中被调用。一个回调函数本质上是一种编程模式(为一个常见问题创建的解决方案),因此,使用回调函数也叫做回调模式
以下是jQuery中使用回调函数简单普遍的例子
$("#btn_1").click(function() {
alert("Btn 1 Clicked");
});
这里它就是回调函数,click方法是一个函数而不是变量,我们将一个函数作为参数传递给了click方法。click方法会调用(或者执行)我们传递给它的函数。这是Javascript中回调函数的典型用法,它在jQuery中广泛被使用。
另一个例子:
var friends = ["Mike", "Stacy", "Andy", "Rick"];
friends.forEach(function (eachName, index){
console.log(index + 1 + ". "+ eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick
});
这里是将匿名函数作为参数传递给了另一个函数或方法。
回调函数的运作方式
因为函数在Javascript中是第一类对象,我们像对待对象一样对待函数,因此我们能像传递变量一样传递函数,在函数中返回函数,在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数时,我们仅仅传递了函数定义。我们并没有在参数中执行函数。我们并不传递像我们平时执行函数一样带有一对执行小括号()的函数。
需要注意的很重要的一点是回调函数并不会马上被执行。它会在包含它的函数内的某个特定时间点被“回调”(就像它的名字一样)。因此,即使第一个jQuery的例子如下所示:
var friends = ["Mike", "Stacy","Andy", "Rick"];
friends.forEach(function (eachName, index){
console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick`
`});
这个匿名函数稍后会在函数体内被调用。即使有名字,它依然在包含它的函数内通过arguments对象获取。
回调函数实际上是闭包
我们将一个回调函数作为变量传递给另一个函数时,这个回调函数在包含它的函数内的某一点执行,就好像这个回调函数是在包含它的函数中定义的一样。这意味着回调函数本质上是一个闭包。
正如我们所知,闭包能够进入包含它的函数的作用域,因此回调函数能获取包含它的函数中的变量,以及全局作用域中的变量。
实现回调函数的几个基本原理
使用命名或者匿名方式作为回调
//全局变量
var allUserData = [];
//普通的logStuff函数,将内容打印到控制台
function logStuff (userData){
if ( typeof userData === "string")
{
console.log(userData);
}
else if ( typeof userData === "object"){
for(var item in userData){
console.log(item + ": " + userData[item]);
``}
``}
}
//一个接收两个参数的函数,后面一个是回调函数
function getInput (options, callback){
allUserData.push(options);
callback(options);
}
//当我们调用getInput函数时,我们将logStuff作为一个参数传递给它
//因此logStuff将会在getInput函数内被回调(或者执行)
getInput({name:"Rich",speciality:"Javascript"}, logStuff);
//name:Rich
//speciality:Javascript
在执行前确保回调函数是一个函数
在调用前最好检查下,作为参数被传递的回调函数是不是确实是一个函数,否则将会出错。
function getInput(options, callback){
allUserData.push(options);
//确保callback是一个函数
if(typeof callback === "function"){
//调用它,既然我们已经确定了它是可调用的
callback(options);
}
}
## 使用this对象的方法作为回调函数时的问题
当this以函数形式调用时,this永远都是window对象。 如果回调函数被传递给一个全局函数,那么this指向window对象中,因为全局函数的this对象指向window对象。
使用call和apply函数
call和apply调用时,this是指定的那个对象
允许多重回调函数
可以将不止一个的回调函数作为参数传递给一个函数,一个函数中可以传入多个回调函数作为参数。
“回调地狱” 问题
在执行异步代码时,无论以什么顺序简单的执行代码,经常情况会变成许多层级的回调函数堆积以致代码变成下面的情形。这些杂乱无章的代码叫做回调地狱因为回调太多而使看懂代码变得非常困难。
两种解决方案
- 给函数命名并传递它们的名字作为回调函数,而不是主函数的参数中定义匿名函数。
- 模块化将你的代码分隔到模块中,这样你就可以导出一块代码来完成特定的工作。然后你可以在你的巨型应用中导入模块
回调函数应用场景
在Javascript编程中回调函数经常以几种方式被使用,尤其是在现代web应用开发以及库和框架中:
- 异步调用(例如读取文件,进行HTTP请求,等等)
- 时间监听器/处理器
- setTimeout和setInterval方法
- 一般情况:精简代码
转载自:https://juejin.cn/post/7033413530636255245