javascript回调函数笔记
来源于:https://github.com/useaname/blog-study
在Javascript中,函数是第一类对象。意味函数可以像对象一样按照第一类被管理使用。
回调函数是从一个叫函数式编程的编程范式中衍生出来的概念。简单来说,函数式编程就是使用函数作为变量。函数式编程过去 - 甚至是现在,依旧没有被广泛使用 - 它过去常被看做是那些受过特许训练的,大师级别的程序员的秘传技巧。
# 什么是回调或者高阶函数
一个回调函数,也被称为高阶函数,是一个被作为参数传递给另一个函数(在这里我们把另一个函数叫做“otherFunction”)的函数,回调函数在otherFunction中被调用。一个回调函数本质上是一种编程模式(为一个常见问题创建的解决方案),因此,使用回调函数也叫做回调模式。
jQuery中的回调函数:
```javascript
$("#btn").click(function(){
alert("btn is clicked");
});
```
正如你在前面的例子中看到的,我们将一个函数作为参数传递给了click方法。click方法会调用(或者执行)我们传递给它的函数。这是Javascript中回调函数的典型用法,它在jQuery中广泛被使用。
```javascript
var friends = ["mike", "stacy", "Andy", "Rick"];
friends.foreach(function(o,i){
console.log(index + 1 + ": " + o);
});
```
回调函数既闭包:
将一个回调函数作为变量传递给另一个函数时,这个回调函数在包含它的函数内的某一点执行。就好像这个回掉函数是在包含它的函数中定义一样。意味着回调函数本质上是一个闭包。
闭包能够进入包含它的作用域,因此回调函数能获取包含它的函数中的变量,以及全局作用域中的变量。
# 实现回调函数的基本原理
### 使用命名或匿名函数作为回调
在前面的例子中,使用了在参数位置定义的匿名函数作为回调函数。这是在回调函数中普遍使用的魔术。另一种常见的是顶一个命名函数并将函数名作为变量传递给函数。比如:
```javascript
//全局变量
var allUserData = [];
//普通函数
function logStuff(userData){
if( typeof userData === "string"){
console.log(userData);
}else if( typeof userData === "object"){
for(var item in userData){
console.log(item + ": " + userData[itme]);
}
}
}
```
//一个函数接收两个参数,后一个参数为回调函数
```javascript
function getInput(options, callback){
allUserData.push(options);
callback(options);
}
//调用getInput时,将logStuff传递给他
//因此logStuff将会在getInput内被回调(执行)
getInput({name:"Rich",speciality:"Javascript"},logStuff);
//name:Rick
//speciality:Javascript
```
# 允许多重回调函数
```javascript
将不止一个的回调函数作为参数传递给一个函数,就像我们能够传递不止一个变量一样。这里有一个关于jQuery中AJAX的例子:
function successCallback(){
//在发送之前做点什么
}
function successCallback(){
//在信息被成功接收之后做点什么
}
function completeCallback(){
//在完成之后做点什么
}
function errorCallback(){
//当错误发生时做点什么
}
$.ajax({
url:"http://fiddle.jshell.net/favicon.png",
success:successCallback,
complete:completeCallback,
error:errorCallback
});
```
# 创建自己的回调函数
使用回调函数是如此的简单而强大,你应该查看你的代码看看有没有能使用回调函数的地方。回调函数将在以下几个方面帮助你:
* 避免重复代码(DRY-不要重复你自己) - 在你拥有更多多功能函数的地方实现更好的抽象(依然能保持所有功能) - 让代码具有更好的可维护性
* 使代码更容易阅读
* 编写更多特定功能的函数
下面的函数将完成:读取用户信息,用数据创建一首通用的诗,并且欢迎用户。这个本来是个非常复杂的函数因为它包含很多if/else语句,且将在调用那些用户数据需要的功能方面有诸多不兼容性。
getUserInput函数是多功能的:它能执行具有多种功能的回调函数。
```javascript
//首先,创建通用诗的生成函数;它将作为下面的getUserInput函数的回调函数
function genericPoemMaker(name, gender){
console.log(name + " is finer than fine wine.");
console.log("Altruistic and noble for the modern time.");
console.log("Always admirably adorned with the latest style.");
console.log("A " + gender + " of unfortunate tragedies who still manages a perpetual smile");
}
//callback,参数的最后一项,将会是我们在上面定义的genericPoemMaker函数
function getUserInput(firstName, lastName, gender, callback) {
var fullName = firstName + " " + lastName;
// Make sure the callback is a function
if(typeof callback === "function"){
// Execute the callback function and pass the parameters to it
callback(fullName, gender);
}
}
//调用getUserInput函数并将genericPoemMaker函数作为回调函数:
getUserInput("Michael", "Fassbender", "Man",genericPoemMaker);
```
因为getUserInput函数仅仅只负责提取数据,我们可以把任意回调函数传递给它。例如,我们可以传递一个greetUser函数:
```javascript
function greetUser(customerName, sex) {
var salutation = sex && sex === "Man" ? "Mr." : "Ms.";
console.log("Hello, " + salutation + " " + customerName);
}
// 将greetUser作为一个回调函数
getUserInput("Bill", "Gates", "Man", greetUser);
// 这里是输出
Hello, Mr. Bill Gate
```
调用了完全相同的getUserInput函数,但是这次完成了一个完全不同的任务。