JavaScript中的回调函数(callback)

前言

callback,大家都知道是回调函数的意思。如果让你举些callback的例子,我相信你可以举出一堆。但callback的概念你知道吗?你自己在实际应用中能不能合理利用回调实现功能? 我们在平时的学习中容易犯不去深究的病,功能实现了也就不再去追其原由,对一些概念模模糊糊。如果对callback没有一个清楚的理解,估计你在学习Node.js后会崩溃,因为callback是Node.js三大核心之一。

一 .回调函数

回调函数的概念

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.

以上是Google的解释,非常清晰简明,小编令人窒息的四级英语水平都能看懂。
下面给一个回调的例子

function doSomething(msg, callback){alert(msg);if(typeof callback == "function") callback();} 
doSomething("回调函数", function(){alert("匿名函数实现回调!");}); 

我们再来看几个经典的回调函数代码,我保证你一定用过他们:

回调函数例子.png

从上面的例子,我们可以看出回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调,这些在我们工作中有很多的使用场景。


二.把使用this对象的函数作为回调函数(陷阱)

当回调函数是一个使用this对象的函数时,我们必须改变执行回调函数的调用对象来保证this对象的上下文。在讲这个问题之前,我们必须先了解JS于this的指向。我们这里不详细谈这个问题,我直接说下自己学习过程总结的判断this指向的两条经验(既然是自己的经验,那就不一定对,希望大家指正):
(1)this的指向是在函数执行的时候确定的,在函数定义的时候是确定不了,实际上this的最终指向的是那个调用它的对象
(2)调用执行函数时,“.”前面是什么,this就是什么。前面没有对象,就是window了。(好粗暴)

回到使用this对象的函数作为回调函数这个问题,我们首先来看看下面这段代码:
//定义一个拥有一些属性和一个方法的对象 //我们接着将会把方法作为回调函数传递给另一个函数

var clientData = {id: 096545,fullName: "Not Set",//setUsrName是一个在clientData对象中的方法setUserName: function (firstName, lastName){this.fullName = firstName + " " + lastName;}
} function getUserInput(firstName, lastName, callback){//code .....//调用回调函数存储callback(firstName, lastName);
}getUserInput("Barack","Obama",clientData.setUserName);console.log(clientData.fullName);  //Not Setconsole.log(window.fullName);  //Barack Obama

在上面的代码中,当clientData.setUsername被执行时,this.fullName并没有设置clientData对象中的fullName属性。相反,它将设置window对象中的fullName属性,这是因为callback中的this指向window的缘故。

使用Call和Apply函数来改变this指向

我们可以使用Call或者Apply函数来解决上面你的问题。到目前为止,我们知道了每个Javascript中的函数都有两个方法:Call 和 Apply。这些方法被用来设置函数内部的this对象以及给此函数传递变量。
这里我们演示Apply函数实现,Call函数类似。(call接收的第一个参数为被用来在函数内部当做this的对象,传递给函数的参数被挨个传递。Apply函数的第一个参数也是在函数内部作为this的对象,然而最后一个参数确是传递给函数的值的数组。)

Apply函数:

//注意到我们增加了新的参数作为回调对象,叫做“callbackObj”
function getUserInput(firstName, lastName, callback ,callbackObj){//code .....callback.apply(callbackObj, [firstName, lastName]);
}getUserInput("Barack", "Obama", clientData.setUserName, clientData);console.log(clientData.fullName); //Barack Obama

使用Apply函数正确设置了this对象,我们现在正确的执行了callback并在clientData对象中正确设置了fullName属性


三.回调函数是实现异步编程的利器

在程序运行中,当某些请求过程漫长,我们有时没必要选择等待请求完成继续处理下一个任务,这时使用回调函数进行异步处理可以大大提高程序执行效率。例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用!
下面有个使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。

function fn(url, callback){var httpRequest;    //创建XHRhttpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   //针对IE进行功能性检测window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;httpRequest.onreadystatechange = function(){if(httpRequest.readystate === 4 && httpRequest.status === 200){  //状态判断callback.call(httpRequest.responseXML); }};httpRequest.open("GET", url);httpRequest.send();
}fn("text.xml", function(){    //调用函数console.log(this);                 / /此语句后输出
});console.log("this will run before the above callback.");  //此语句先输出

我们请求异步处理,意味着我们开始请求时,就告诉它们完成之时调用我们的函数。在实际情况中,onreadystatechange事件处理程序还得考虑请求失败的情况,这里我们是假设xml文件存在并且能被浏览器成功加载。这个例子中,异步函数分配给了onreadystatechange事件,因此不会立刻执行。
最终,第二个console.log语句先执行,因为回调函数直到请求完成才执行。

在Javascript编程中回调函数经常以几种方式被使用,尤其是在现代web应用开发以及库和框架中:

  • 异步调用(例如读取文件,进行HTTP请求,动态加载js文件,加载iframe资源后,图片加载完成执行回调等等)
  • 事件监听器/处理器
  • setTimeout和setInterval方法
  • 一般情况:精简代码

4.“回调地狱”问题以及解决方案

这么多回调嵌套,我还没遇到过。下面内容是直接从网上copy过来,大家看下,还是很好理解的。
在执行异步代码时,无论以什么顺序简单的执行代码,经常情况会变成许多层级的回调函数堆积以致代码变成下面的情形。这些杂乱无章的代码叫做回调地狱因为回调太多而使看懂代码变得非常困难。我从node-mongodb-native,一个适用于Node.js的MongoDB驱动中拿来了一个例子。这段位于下方的代码将会充分说明回调地狱:

var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory});p_client.open(function(err, p_client) {p_client.dropDatabase(function(err, done) {p_client.createCollection('test_custom_key', function(err, collection) {collection.insert({'a':1}, function(err, docs) {collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {cursor.toArray(function(err, items) {test.assertEquals(1, items.length);// Let's close the dbp_client.close();});});});});});});

你应该不想在你的代码中遇到这样的问题,当你当你遇到了-你将会是不是的遇到这种情况-这里有关于这个问题的两种解决方案。

给你的函数命名并传递它们的名字作为回调函数,而不是主函数的参数中定义匿名函数。
模块化L将你的代码分隔到模块中,这样你就可以到处一块代码来完成特定的工作。然后你可以在你的巨型应用中导入模块。



作者:echozzh
链接:https://www.jianshu.com/p/84cc8732689c
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript构造函数类和原型prototype定义的属性和方法的区别

1、把方法写在原型中比写在构造函数中消耗的内存更小,因为在内存中一个类的原型只有一个,写在原型中的行为可以被所有实例共享, 实例化的时候并不会在实例的内存中再复制一份 而写在类中的方法,实例化的时候会在每个实例中再复制一…

[css] 如何禁用移动的选择高亮?

[css] 如何禁用移动的选择高亮? *{ -webkit-touch-callout:none; /*系统默认菜单被禁用*/ -webkit-user-select:none; /*webkit浏览器*/ -khtml-user-select:none; /*早期浏览器*/ -moz-user-select:none;/*火狐*/ -ms-user-select:none; /*IE10*/ user-sele…

原型 原型链 call / apply

原型定义: 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承原型的属性和方法。原型也是对象。 利用原型特点和概念,可以提取共有属性。对象如何查看原型 ——> 隐…

Open-Falcon 监控系统监控 MySQL/Redis/MongoDB 状态监控

背景: Open-Falcon 是小米运维部开源的一款互联网企业级监控系统解决方案,具体的安装和使用说明请见官网:http://open-falcon.org/,是一款比较全的监控。而且提供各种API,只需要把数据按照规定给出就能出图&#xff0c…

[css] 使用css实现悬浮提示文本

[css] 使用css实现悬浮提示文本 <div class"tips-demo" data-tips"提示文本">演示文本</div><style> .tips-demo {position: fixed;bottom: 15px;right: 15px; }.tips-demo:after {content: attr(data-tips);position: absolute;top: 0…

JavaScript之继承模式,命名空间,对象枚举

继承发展史 1-传统形式 → 原型链 过多的继承了没用的属性&#xff08;很好理解&#xff0c;不用代码演示了&#xff09; 2-借用构造函数 不能继承借用构造函数的原型&#xff08;很好理解&#xff0c;不用代码演示了&#xff09;每次构造函数都要夺走一个函数&#xff08;很…

delphi dxBarManager 的dxBarEdit 输入问题

Developer Express 6 想做像office2007那样界面.问题:dxBarManager1 里面添加了cxBarEditItem1 这是个文本框,运行可以输入内容,但是当焦点失去时,刚刚输入的内容没了.只能每次输完内容后一定要按回车才能保存内容.这里面所有能改变值的控件都是这样子的,有没有什么办法可以在控…

[css] 怎么设置可点击的元素上强制手型?

[css] 怎么设置可点击的元素上强制手型&#xff1f; cursor 属性个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

什么是KYC,KYC认证的重要性

KYC&#xff0c;是英语Know Your Customer的简称&#xff0c;这段词汇用翻译直接生硬的翻译过来意思是&#xff1a;了解你的客户。词义翻译的非常的直接。不过却缺乏一些诗意。我们在万能的度娘上键入KYC得到的解释是&#xff1a;是金融机构、银行、交易所等企业必须进行的一项…

虚拟机上的Linux学习

title: 虚拟机上的Linux学习 date: 2018-08-08 15:48:28 updated: tags: [Linux,学习笔记] description: keywords: comments: image: --- 开始学习Linux了,还没有掌握系统完全备份的技术,所以不敢直接在物理机器上安装Linux,我选择使用虚拟机安装. 使用虚拟机安装Linux 最开始…

[css] 如何使用css实现跨浏览器的最小高度?

[css] 如何使用css实现跨浏览器的最小高度&#xff1f; div{height:auto!important; height:200px; min-height:200px; } 这个第一个已经 important 了&#xff0c;后面的属性设置应该也没用了吧 浏览器兼容接触的比较少了&#xff0c;目前项目只兼容 blink个人简介 我是歌谣&…

Promise解决多个异步Ajax请求导致的代码嵌套问题(完美解决方案)

这篇文章主要介绍了用Promise解决多个异步Ajax请求导致的代码嵌套问题(完美解决方案),需要的朋友可以参考下 问题 前端小同学在做页面的时候&#xff0c;犯了个常见的错误&#xff1a;把多个Ajax请求顺序着写下来了&#xff0c;而后面的请求&#xff0c;对前面请求的返回结果…

[css] 使用css3实现一个斑马线的效果

[css] 使用css3实现一个斑马线的效果 ferrinweb 如果需要很多或者无限扩展的斑马线&#xff0c;你这个方案就有缺点了 cxwht 你的方案需要增加额外的元素&#xff0c;不太理想 最好的办法是用渐变背景实现 linear-gradient( [ [ <angle> | [top | bottom] || [left | ri…

最详细的后缀数组

写在前面&#xff1a; 多余的我就不提了&#xff0c;只是觉得网上的博客吧流程&#xff0c;每个数组存的是下标还是值&#xff0c;都讲的不是很清楚&#xff08;让我这种蒟蒻很是困扰&#xff09; 相信到现在这种水平的都可以知道什么是倍增&#xff0c;为什么能倍增都比较清楚…

promise简单封装ajax 完美嵌套多个ajax请求

转载请注明出处并留个言哈&#xff0c;分享快乐~&#xff01; request.js文件&#xff0c;注意网页头部script标签加载顺序 function myAjax(json, callback) {var p new Promise(function (resolve, reject) {$.ajax({url: json.url, //请求的url地址dataType: json.dat…

[css] 使用纯css来创建一个滑块

[css] 使用纯css来创建一个滑块 .checke{position: relative;-webkit-appearance: none;width:90px;height: 44px;line-height: 44px;background: #eee;border-radius: 30px;outline: none;}.checke:before{position: absolute;left: 0;content: ;width: 44px;height: 44px;bor…

纯静态网站模板封装header和footer

前后端分离的网站模板&#xff0c;如果不用任何渲染引擎&#xff0c;能否封装公共的header和footer&#xff08;或其它html公共代码呢&#xff09;&#xff1f; 答案是肯定的&#xff0c;因为jQuery有一个函数叫 load &#xff0c;可以在浏览器绘制页面之前加载完整的 html 页…

SAP字体调节大小

登陆SAP 之后&#xff0c;菜单下面一行&#xff0c;最右边的那个彩色按钮&#xff08;SAP GUI&#xff09;&#xff0c;点击“选项”-可视设计-字体设计-固定狂赌字体设计&#xff0c;点击&#xff1a;选择字体 即可。转载于:https://www.cnblogs.com/RogerLu/p/9612648.html

javascript中对一个对象数组按照对象某个属性进行排序

在javascript中&#xff0c;对象和数组是两种不同的类型&#xff0c;这和php中的数组概念不同。在javascript中&#xff0c;也有一些精妙的算法&#xff0c;用来对一些对象进行排序。我在面试迅雷的时候&#xff0c;也拿到一道题&#xff0c;当时做题的时候考虑到时间&#xff…

[css] 用css画一个五边形和一个六边形

[css] 用css画一个五边形和一个六边形 五边形&#xff1a;clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); 六边形&#xff1a;clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); 七边形&#xff1a;clip-path: polygon(50% 0%…