通过对网络上一些关于回调函数的了解与学习,自己归纳出自己对于回调函数的一些认识与理解,有一些不足的地方还望大家见谅,大家也可以留言给出自己的意见......
一:什么是回调或者高阶函数
一个回调函数,也被称为高阶函数,是一个被作为参数传递给另一个函数(otherFunction)的函数,回调函数在otherFunction中被调用。一个回调函数本质上是一种编程模式,因此,使用回调函数也叫做回调模式。
$("#btn_1").click(function(){
alert("Btn --1 Clicked");
});
将一个函数作为参数传递给click方法。click方法会调用我们传递给它的函数。这是一个JavaScript中回调函数的典型用法,它在JQuery中广泛使用。
一个JavaScript中典型的回调函数例子:
var items = ["A", "B", "C", "D"];
items.forEach(function(eachName, index){
console.log(index + 1 + '.' + eachName);
});
二:回调函数是如何运作的?
因为函数在JavaScript中是第一类对象,我们像对待对象一样对待函数,因此我们能像传递变量一样传递函数,在函数中返回函数,在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数时,我们仅仅传递了函数定义。我们并没有在参数中执行函数。我们并不传递像我们平时执行函数一样带有一对小括号()的函数。
需要注意的很重要的一点是回调函数并不会马上被执行。它会在包含它的函数内的某个特定时间被“回调”。
三:回调函数是闭包
能够将一个回调函数作为变量传递给另一个函数时,这个回调函数在包含它的函数内的某一点执行,就好像这个回调函数是在它包含的函数中定义一样。这意味着回调函数本质上是一个闭包。
闭包能够进入包含它的函数的作用域,因此回调函数能够获取包含它的函数中的变量,以及全局作用域中的变量。
四:实现回调函数的基本原理
1:使用命名或匿名函数作为回调
使用在参数位置定义的匿名函数作为回调函数。这是在回调函数使用中的一种普遍的模式。另一种常见的模式是定义一个命名函数并将命名函数名作为变量传递给函数。
//全局变量
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
2:传递参数给回调函数
既然回调函数在执行时仅仅是一个普通函数,我们就能给它传递参数。我们能够传递任何包含它的函数的属性(或者全局属性)作为回调函数的参数。
//全局变量
var generalLastName = "Cliton";
function getInput (options, callback){
allUserData.push (options); //将全局变量generalLastName传递给回调函数
callback(generalLastName,options);
}
3:在执行之前确保回调函数是一个函数
在调用之前检查作为参数被传递的回调函数确实是一个函数,这样的做法是明智的。这也是一个实现条件回调函数的最佳时间。
function getInput(options, callback){
allUserData.push(options);
// 确保callback是一个函数
if(typeof callback === 'function'){
// 调用它,当判断为一个可调用的函数时
callback(options);
}
}
4:使用this对象的方法作为回调函数时的问题
当回调函数是一个this对象的方法时,我们必须改变执行回调函数的方法来保证this对象的上下文。否则如果回调函数被传递给一个全句函数,this对象要么指向全局window对象。要么指向包含方法的对象。
var clientData = {
id: 094545,
fullname: "Not Set",
// setUserName 是一个在clientData对象中的方法
setUserName: function( firstname, lastName){
// 这里指向了对象中的fullName属性
this.fullName = firstName + " " + lastName;
}
}
function getUserInput(firsrtName, lastName, callback){
// 存储names
callback( firstName, lastName);
}
注:当clientData.setUserName被执行时,this.fullName并没有设置clientData对象中的fullName属性。相反,它将设置window对象中的fullName属性,因为getUserInput是一个全局函数。因为全局函数中的this指向window对象。
getUserInput( "Barack", "Obama", clientData, setUserName);
console.log(clientData.fullName); // Not Set
console.log(window.fullName); // Barack Obama
5:使用Call和Apply函数来保存this
每个JavaScript中的函数都有两个方法:Call 和 Apply。而这些函数被用来设置函数内部的this对象以及给此函数传递变量。call 接受的第一个参数为被用来在函数内部当做 this 的对象,传递给函数的参数被挨个传递。apply函数的第一个参数也是在函数内部作为 this 的对象,然而最后一个参数却是传递给函数的值的数组。
例:
// 使用Apply
function getUserInput01(firstName, lastName, callback, callbackObj){
callback.apply(callbackObj, [firstName, lastName]);
}
// 我们将clientData.setUserName方法和clientData对象作为参数,clientData对象会被Apply方法使用来设置this对象
getUserInput01('Chris', 'Paul', clientData.setUserName, clientData);
// clientData 中的fullName属性被正确设置
console.log(clientData.fullName);
// 使用Call
function getUserInput02(firstName, lastName, callback, callbackObj){
callback.call(callbackObj, firstName, lastName);
}
getUserInput02('Tracy', 'McGrady', clientData.setUserName, clientData);
console.log(clientData.fullName);
6:允许多重回调函数
我们可以将不止一个的回调函数作为参数传递给一个函数,就像我们能够传递不止一个变量一样。
function successCallback(){
// 在信息被成功接收之前做点什么
}
function complteCallback(){
// 在完成之后做点什么
}
function errorCallback(){
// 当错误发生时做点什么
}