理解回调函数
2017-12-06 19:18
106 查看
前言
最近在看Node.js,有介绍一些关于回调函数的内容,之前在js里面有用过,但是只是知道要那样用,为什么要这样做和这样做有什么用处并不清楚。自己查了一些资料,理解了一下,记录下来作为回顾也方便之后复习。
一、什么是回调函数?
A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.例如:
function Cat(words, callback) { callback(words); } function Speak(words) { console.log(words); } Cat("miao", Speak); Cat("miao", function(words) { console.log(words); });
上述代码Cat中的Speak函数和匿名函数就被称为回调函数。
然后再来看一段代码:
function f1() { console.log("f1 finished."); } function f2(cb) { cb(); console.log("f2 finished."); } //执行结果: f1 finished. // f2 finished.
那么问题来了,不是说回调函数最后执行吗????
对,很多介绍回调函数的例子讲到这里是就完了,异步回调函数的确是应该在函数的最后执行,不过上面的例子是一个同步回调函数,函数的执行顺序依然自上而下顺序执行。 那么什么是异步回调呢? 我们又怎么实现异步回调呢? 请往下看。
异步回调函数:
function f2() { console.log('f2 finished'); } function f1(cb) { setTimeout(cb,1000); //用setTimeout()模拟耗时操作 console.log('f1 finished'); } f1(f2); //得到的结果是 f1 finished ,f2 finished
因为setTimout()是异步函数,所以这里是先将f1执行完后再执行的回调函数f2。
小结:因为函数在Javascript中是第一类对象,我们像对待对象一样对待函数,因此我们能像传递变量一样传递函数,在函数中返回函数,在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数是,我们仅仅传递了函数定义。我们并没有在参数中执行函数。【需要注意的很重要的一点是回调函数并不会马上被执行。它会在包含它的函数内的某个特定时间点被“回调”。就好像它是在这个函数里面定义的,这意味着回调函数本质上是一个闭包。正如我们所知,闭包能够进入包含它的函数的作用域,因此,回调函数能获取包含它的函数中的变量,以及全局作用域中的变量。】最后,强调一点,并不是使用了回调函数就是异步,回调函数只是异步的一种实现方式而已。
二、为什么要使用回调函数?
可能有人想问,那为什么不直接从Cat函数里面调用Speak呢???如果你直接在函数Cat里调用的话,那么这个回调函数就被限制死了。但是使用函数做参数就有下面的好处:当你Cat(Speak)的时候函数Speak就成了回调函数,而你还可以Cat(Smell)这个时候,函数Smell就成了回调函数。如果你写成了function Cat(){…;Speak();}就失去了变量的灵活性。另外一点是,当函数的实现过程非常漫长,你是选择等待函数完成处理,还是使用回调函数进行异步处理?这种情况下,使用回调函数变得至关重要,例如:AJAX请求,。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用。
三、使用回调函数应该注意些什么?
1.使用命名或匿名函数作为回调2.在执行之前确保回调函数是一个函数
3.使用this对象的方法作为回调函数时的问题:
当回调函数是一个this对象的方法时,我们必须改变执行回调函数的方法来保证this对象的上下文。否则如果回调函数被传递给一个全局函数,this对象要么指向全局window对象(在浏览器中)。要么指向包含方法的对象。
例如:
var localData = { id: 094545, name :"nothing", //setUsrName是一个在clientData对象中的方法 setName: function (name){ //这指向了对象中的fullName属性 this.name = name; } } function getName(name, callback){ callback(name); } getName("Tom",localData.setName); console.log(localData.name); //nothing console.log(window.name); //Tom
当你执行getName函数时,因为getName函数是一个全局函数,所以它上下文是getName的上下文,是全局window对象,所以它将设置window对象的name属性为“Tom”。
4.使用Call和Apply函数来保存this:
为了解决3的问题,我们通常使用apply或者call。当需要用到this的时候,我们只需在函数中加一个参数,以确定我们的上下文对象。例如:
function successCb() { //... } function errorCb() { //... } $.ajax({ type:"get", url:"http://localhost/index.php", data:{uid:id,password:password}, dataType:"jsonp", jsonp:"callback", success:successCb, error:errorCb, });
四、总结
在Javascript编程中回调函数经常以几种方式被使用,尤其是在现代web应用开发以及库和框架中:1)异步调用(例如读取文件,进行HTTP请求,等等)
2)时间监听器/处理器
3)setTimeout和setInterval方法
4)一般情况:精简代码
相关文章推荐
- 关于回调函数的一些理解
- 彻底理解javascript的回调函数(推荐)
- 深入理解Node.js 事件循环和回调函数
- 关于回调函数 理解一下
- 深入理解回调函数 (转载)
- Java中什么是接口回调?and Java回调函数的理解
- Java回调函数的理解
- 【Shawn-JavaScript】回调函数的理解
- 理解和使用 JavaScript 中的回调函数
- 回调函数(真好理解)
- 回调函数透彻理解Java
- 对c语言回调函数的理解
- 深入理解Java回调函数
- 重新理解javascript回调函数
- callback回调函数的理解
- java超简单的android安卓回调函数的小范例理解
- 回调函数的理解
- 理解javascript 回调函数
- Java回调函数的理解
- 透彻理解Java回调函数