javascript之回调函数
2018-01-04 16:39
162 查看
回调函数
在javascript中,Function也是一种类型,方法在js中也是一种对象。所以函数可以作为一个参数传递到另一个函数中,并随后执行。或者是函数可以作为另一个函数(外层函数)的返回值,之后可以执行这个返回的函数。而这个特性,正好是回调函数的精髓。回调函数的概念源自函数编程范例,在函数编程范例范例中详细说明了函数作为参数来使用的情况。
定义
那么什么是回调函数呢?回调函数是一个作为参数被传递给另一个函数(称“otherFunction”)的函数,回调函数在"otherFunction"中被调用(或执行)。回调函数本质上是一种模式(模式就是解决一类共性问题的解决方法),回调函数的使用就称为是一种回调模式。
现给出一个回调函数在jQuery中的常用实例:
$("#btn_1").click(function() { alert("Btn 1 Clicked"); });在上面的代码中,将函数作为参数传入到click方法中,当点击鼠标,触发click事件时,会调用这个函数。
现在,我们再看一个在javascript中使用回调函数的例子:
var friends = ["Mike", "Stacy", "Andy", "Rick"]; friends.forEach(function (eachName, index){ console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick });在forEach方法中,传入匿名函数(没有名字的方法)作为参数。
回调函数的工作原理
我们可以像变量一样传递函数,作为另一个函数的返回值,也可以在其他函数中调用它。当我们将回调函数作为参数传递给另一个函数的时候,我们传递的仅仅是函数定义,并没有在传递参数过程中执行回调函数。而包含函数(回调函数的传入函数)的参数中包含了回调函数的定义,所以包含函数可以在任何时候执行回调函数。
注意,回调函数不是立即执行的,而是会在包含函数中的某些地方被“回调”。在之前给出的click例子中,即使回调函数作为参数传入到函数中,它也不会立即执行,而是会在函数体中被延迟调用。虽然是一个匿名函数,但是可以通过包含函数的arguments对象来访问匿名函数。
回调函数是闭包
当将回调函数作为一个参数传递给另一个函数的时候,回调函数会在包含函数体内的指定地方被执行,就好像这个回调函数是在包含函数体内定义的一样。这就意味着回调函数就是一个闭包。我们都知道,闭包可以访问包含函数的作用域,所以回调函数也可以访问包含函数的变量,甚至是全局作用域中的变量。实现回调函数的基本规则
虽然回调函数简单,但是在我们生成回调函数的时候,需要注意一些规则。(1)作为回调函数的函数可以是有名字的,也可以是匿名的
在之前的例子中,我们已经看到了匿名函数作为回调函数的用法。这是使用回调函数常用的模式。另一种方法是,使声明一个命名的函数,然后将函数名作为参数进行传递(注意传递的只有函数名,没有())。如下例:
//全局变量 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[item]); } } } // 一个需要传入两个参数的函数,第二个参数是一个回调函数 function getInput (options, callback) { allUserData.push (options); callback (options); } //当我们调用getInput方法的时候,logStuff作为一个参数 //logStuff将会成为在实际运行中被回调的回调函数 getInput ({name:"Rich", speciality:"JavaScript"}, logStuff); // name: Rich // speciality: JavaScript
(2)给回调函数传递参数
回到函数在执行过程中和普通函数是一样的,也可以为回调函数传递参数。可以将包含函数中的属性或者是全局属性作为参数传递给回调函数。在上一个例子中,我们将options(包含函数的属性)传递给了回调函数。下面我们试着将全局变量和局部变量传递给回调函数:
//Global variable var generalLastName = "Clinton"; function getInput (options, callback) { allUserData.push (options); // Pass the global variable generalLastName to the callback function callback (generalLastName, options); }
(3)在执行回调函数前,检查回调函数是否为函数
在调用以函数参数传入的回调函数前,需要检查是否为一个函数。
function getInput(options, callback) { allUserData.push(options); // Make sure the callback is a function if (typeof callback === "function") { // Call it, since we have confirmed it is callable callback(options); } }如果getInput函数没有做适当的检查(检查callback是否是函数,或是否通过参数传递进来了),我们的代码将会导致运行时错误。
(4)使用带有this对象的函数作为回调函数的情况
当使用带有this对象的方法作为回调函数时,我们要改变我们执行回调函数的方式,以确保this对象的上下文环境。否则,当回调函数被传递给一个全局函数时,要么this对象指向了window对象,要么this对象将指向包含函数对象。
var clientData ={ id : 1234, fullname : "no-name", setUserName : function(firstname,lastname){ this.fullname = firstname + " "+lastname; } } function getUserInput(firstname,lastname,callback){ callback(firstname,lastname); } getUserInput("Barack","obama",clientData.setUserName); console.log(clientData.fullname);//no-name console.log(window.fullname);//Barack obama
当clientData.setUserName作为回调函数被执行的时候,this.fillname将不会设置clientData对象中的fullname的值。事实是,将会设置window对象的fullname的值,因为getUserInput是一个全局函数,在全局函数中的this对象将指向window对象。
(5)使用call或apply方法保护this的内容
每个函数都有call和apply方法,通过这两个方法,能够指定函数在哪个对象上执行。
var clientData ={ id : 1234, fullname : "no-name", setUserName : function(firstname,lastname){ this.fullname = firstname + " "+lastname; } } function getUserInput(firstname,lastname,callback,callbackObj){ callback.apply(callbackObj,[firstname,lastname]); } getUserInput("Barack","obama",clientData.setUserName,clientData); console.log(clientData.fullname);//Barack obama
(6)可以传递多个回调函数给另一个函数,就像传递多个变量一样。
回调函数的使用是如此简单,但功能强大。当有以下需求时可以考虑使用回调:
避免重复代码 (DRY—Do
Not Repeat Yourself)
在你需要更多的通用功能的地方更好地实现抽象(可处理各种类型的函数)。
增强代码的可维护性
增强代码的可读性
有更多定制的功能
先给出一个实例,说明使用回调函数,避免了繁琐冗余的代码,使用一个函数,通过调用不同的回调函数,实现多个功能,简化代码。
//该函数的作用是根据输入的人名和性别,输出一首诗 function genericPoemMaker(name,gender){ console.log(name + "is finer than fine wine"); console.log("A"+gender+" of unfortunate tragedies who still manages a perpetual smile."); } //该函数的作用是根据输入的人名和性别,输出问候语 function greetUser(customername,sex){ var salutation = sex && sex === "man" ? "Mr.":"Ms."; console.log("hello,"+salutation+" "+customername); } //输入人名,然后执行回调函数 function getUserInput(firstname,lastname,gender,callback){ var fullname = firstname + " "+ lastname; if(typeof callback ==="function"){ callback(fullname,gender); } } getUserInput("michael","faster","man",genericPoemMaker); getUserInput("michael","faster","man",greetUser);
在上面的示例中,输入人名和性别后,可以实现各种操作,只需要替换不同的回调函数就可以了。
参考资料
Understand JavaScript Callback Functions and Use Them
理解和使用 JavaScript 中的回调函数
相关文章推荐
- javascript的回调函数 同步 异步
- 理解和使用 JavaScript 中的回调函数
- javascript的回调函数
- javascript 自定义回调函数
- javascript 回调函数用法演示
- 浅谈javascript回调函数
- Javascript 中的回调函数和递归函数简单实际分析学习
- javascript判断css3动画结束 css3动画结束的回调函数
- Javascript中的回调函数
- 理解和使用 JavaScript 中的回调函数
- 理解和使用 JavaScript 中的回调函数
- JavaScript回调函数陷阱
- JavaScript中回调函数的上下文问题
- 理解javascript 回调函数
- JavaScript-回调函数
- 理解和使用 JavaScript 中的回调函数
- 理解javascript中的回调函数(callback)
- JavaScript ES7 中使用 async/await 解决回调函数嵌套问题
- 谈谈JavaScript自定义回调函数
- javascript的回调函数