平常的前端开发工作中,编写js时会有很多地方用到函数的回调。

最简单的例子就是:

以上只能回调没有参数的(除法你事先知道回调的函数的参数),如果函数有未知的函数,就不能如此简单的调用了。

高级方法:

1、使用javascript的call方法

function doSomething(callback,arg1,arg2) {callback.call(this,arg1,arg2);}function foo(arg1,arg2) {alert(arg1+":"+arg2);}doSomething(foo,1,2); /* 弹出了1:2 */2、使用javascript 的 apply方法function doSomething(callback,args) {callback.apply(window,args);}function foo(arg1,arg2) {alert(arg1+":"+arg2);}doSomething(foo,[1,2,3]); /* 弹出了1:2 */

可以看成call和apply基本一样,区别就是call只能一个个传参数,apply只能把参数放数组里传进来。

他们的第一个参数都是作用域,比如上面传了this,表示就是和doSomething这个函数一样的作用域,当然你也可以传window,表示整个window的作用域。

3、apply的巧妙用法

apply也可以看作是函数的执行函数,就是用来执行某个函数的函数。所以你会发现,有时候用好apply,有很多原本繁杂的事情会变得如此简单。

比如数组的push方法使用apply来调用:

var arr1=[1,3,4];

var arr2=[3,4,5];

如果我们要把 arr2展开,然后一个一个追加到arr1中去,最后让arr1=[1,3,4,3,4,5]

arr1.push(arr2)显然是不行的。 因为这样做会得到[1,3,4,[3,4,5]]

我们只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身)

var arrLen=arr2.lengthfor(var i=0;i

自从有了Apply,事情就变得如此简单

Array.prototype.push.apply(arr1,arr2)

一行代码就解决了,原理能看的出来,Array.prototype.push是指数组的push函数,apply(arr1,arr2)说明arr1是作用域,就等同于是arr1调用了数组的push函数,

而且arr1的确就是个数组,所以可以调用,arr2表示入参的数组。所以,以上语句等同于:arr1.push(3,4,5)。(push函数支持传递多个入参,这也是这里可以使用apply的前提条件)

以上语句也可以写成:arr1.push.apply(arr1,arr2); 两者完全等效,因为arr1.push表示arr1的push函数,也就是数组的push函数。

如果使用call就是这样Array.prototype.push.call(arr1,arr2[0],arr2[1]...),显然还是apply合适。

要是你还问,那直接用arr1.push(3,4,5)不就行了,那已经暴露了你的智商,arr2又不是不可以变,下次不是[3,4,5]了呢。

还有获取数组中,最大的那个数字,也可以使用apply调用Math.max函数

var arr1=[1,3,4];

alert(Math.max.apply(window,arr1)); /* 作用域可以不是window,就算是null都行,Math.max.apply(this,arr1),Math.max.apply(null,arr1) */

4、工作中函数回调的实际例子

有了上面的基础,就能看的懂工作中封装好的js的回调函数了

背景:页面A需要使用页面B来选择某个项目,然后带回这个项目的信息给页面A,页面A根据这些信息丰富自己。

页面A:

noticeInfo = {selectProject: function () {var win = newsee.ui.windowwin.show('项目列表', '../Project/ProjectSelectList.html?callback=noticeInfo.setProjectInfo', { size: win.winSizeType.big })//在当前页面弹出框,框里面是另一个页面,地址后面带上需要回调的函数名//注意这两个页面其实都是在一个页面里面的,并不是像window.open()那样出现了新窗口,所以两个页面的js都是可见的},setProjectInfo: function (obj) {//回调函数,将选择好的项目对象传进来,然后丰富自己的页面$('#projectName').val(obj.name)$('#projectID').val(obj.id)}}

页面B:

function SelectBack() {var callback = newsee.util.url.getQuery('callback'); //获取页面参数callback,这里获取到的是"noticeInfo.setProjectInfo",是个字符串var arr = newsee.ui.grid.getSelectedBack('datagrid') //获取选择的项目,这个不用深究if (!arr.length) {return newsee.ui.window.alert('请选择项目!')}newsee.util.url.back(callback, arr[0]) //重点来了,这里执行回调,将需要回调的函数名和入参传进来,arr[0]就是选择的项目的对象的数组了(它也是个数组,里面就一个对象)}newsee.util.url.back函数如下:back : function (funcName) {// / 返回时执行的方法,一般为重新绑定var isWindow = typeof $$winClose === 'function',// 是否为弹窗args // 弹窗返回方法参数if (isWindow) {// 弹窗的返回方法$$winClose()args = [].slice.call(arguments) //arguments大家应该都知道的吧,它可以用来获取函数的实参,它类似数组又不是数组,这句代码就是把它转换成数组,因为apply的入参需要是个数组才行//args现在里面有两个元素,args[0]=callback,就是之前传进来的回调函数名,args[1]=arr[0],就是回调函数的入参newsee.callFunc.apply(newsee, args) //执行 newsee.callFunc 函数,作用域就是newsee自己(等同于newsee自己调用callFunc函数),参数是args}}

newsee.callFunc函数如下:

callFunc: function(funcName, arg) {var func = typeof funcName === 'function' ? funcName : this.findItem(window, funcName) //上面我有提到过,doSomething("foo"); 传入的是一个字符串,不是一个函数名,所以无法执行//同样的道理,现在funcName=args[0]=callback="noticeInfo.setProjectInfo",是个字符串,不能直接调用apply,需要变成函数//这句话就是用来判断funcName是不是一个函数,如果不是,就在window作用域里根据funcName找到这个函数,然后赋给funcif (typeof func === 'function') {//此时func已经是个函数了,就是页面A里定义的noticeInfo.setProjectInfo()try {return func.apply(window, arg) //执行需回调的函数,作用域依然是window,反正这个函数在window里肯定能找到,参数就是arg=args[1]=arr[0],即之前在页面B获取到的项目对象}catch (e) {console.error(e)}}}

ok,需回调的函数就这样被执行了,至于怎么根据字符串形式的函数名获取这个函数,看下面。

//findItem函数如下:findItem: function(data, key) {// / 获取对象指定键的值if (this.include(data, key)) { //data这里就是传进来的window,注意window就是一个对象,首先判断window对象里是否存在"noticeInfo.setProjectInfo"这个属性return eval('data.' + key) //如果存在,就执行"data.noticeInfo.setProjectInfo",这样就获取到了这个函数了。(eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码)}}//include函数如下:include: function(data, key) {// / 判断对象是否存在键值if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') {return false}var keys = key.split('.'),item = data,result = truekeys.forEach(function(k) {if (item != null && typeof item === 'object' && k in item) {//依次循环遍历,第一次item = data,那就是window这个对象,k="noticeInfo",window[noticeInfo]是存在的,因为在页面A里定义了noticeInfo这么一个对象//第二次循环,item=window.noticeInfo,k="setProjectInfo",window.noticeInfo[setProjectInfo]也是存在的,因为在页面A里也定义了setProjectInfo这么一个函数//这里没有第三次循环了,所以最后返回是true,说明window对象里存在"noticeInfo.setProjectInfo"这个属性,接下来使用eval()拿到它即可item = item[k]} else {return result = false}})return result}

对eval() 函数也介绍一下:

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。

返回值就是通过计算 string 得到的值(如果有的话)。如:

eval("x=10;y=20;document.write(x*y)") //输出 200document.write(eval("2+2")) //输出 4var x=10document.write(eval(x+17)) //输出 27

所以上面的eval('data.' + key)就是执行"data.noticeInfo.setProjectInfo"这个字符串,

因为data在这里就是指window,所以返回值就是window.noticeInfo.setProjectInfo()这个函数

其实可以在简单一点,根本没必要使用eval()来获取这个函数,因为在include函数里,item就已经是window.noticeInfo.setProjectInfo这个对象了,这个对象就是我们想要的函数。

(在js中函数也是对象,函数名就是这个函数的引用,就和地址差不多)

既然都拿到这个函数了,直接返回不就行了,所以上面的include()和findItem可以这样简化:

include: function(data, key) {if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') {}else{var keys = key.split('.'),item = data,result = truekeys.forEach(function(k) {if (item != null && typeof item === 'object' && k in item) {item = item[k]} else {result = false;}})if(result)return item}},findItem: function(data, key) {return this.include(data, key)

经过测试,发现这两个根据字符串形式的函数名获取函数的方法都可以达到一模一样的效果。

alert回调_你知道javascript函数的回调怎么用吗?相关推荐

  1. java调用javascript函数_[Java教程]JavaScript函数的4种调用方法详解

    [Java教程]JavaScript函数的4种调用方法详解 0 2016-08-09 00:00:12 在JavaScript中,函数是一等公民,函数在JavaScript中是一个数据类型,而非像C# ...

  2. javascript 函数的回调和递归

    前言 先来看看我们为什么要使用函数: 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它 ...

  3. 多方法接口回调_浅析接口定义和接口回调

    目录 一.接口定义 二.接口的特点 三.使用接口的好处 四.接口回调 五.Android中的接口回调机制 一.接口定义 接口通常以interface来修饰. public interface Anim ...

  4. alert 回调_立即执行函数与回调函数

    立即执行函数 语法:()()(function(){alert(1)})()第一个括号中 输入如何定义一个函数第二个括号 用来调用这个函数传参:第一个括号中传递的是形参第二个括号中传递的是实参 在哪会 ...

  5. bootstraptable 加载完成回调函数_牛皮了!头一次见有大佬把「JavaScript中的回调函数」详解得如此清晰明了...

    前言 callback,大家都知道是回调函数的意思.但是你对这个概念应该是模模糊糊.比如Ajax,你只知道去调用返回函数,如果对callback没有理解清楚,估计你在学习Node.js后会崩溃,因为c ...

  6. 理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被"存储"在变量中,能作为函数参数被传递,能在函数中被创建, ...

  7. 理解javascript中的回调函数(callback)【转】

    在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...

  8. 关于javascript中的回调函数

    关于javascript中的回调函数 原文地址:http://blog.csdn.net/sicluoyi/article/details/1737969 考虑一个这样的例子: 假如某个项目的底层和高 ...

  9. JavaScript高级day01-PM【对象、函数、回调函数、IIFE、this、关于语句分号问题、webstorm代码模板、复习】

    笔记.视频.源码:JavaScript(基础.高级)笔记汇总表[尚硅谷JavaScript全套教程完整版] 目   录 P7 07.尚硅谷_JS高级_对象 23:30 1. 什么是对象? 2. 为什么 ...

最新文章

  1. 4 OC 中的内存分配以及内存对齐
  2. 双流棠湖中学怎么样_全川前十高中,棠湖中学后来居上,七中、四中、成外是“大佬”...
  3. 在QT中结构体快速从二进制文件中读取数据
  4. macappstore登不上去_荣耀亲选一度登机箱----一个安静得想放进大侄子的magic box
  5. linux qt小型计算器,Qt实现一个简单的计算器
  6. 优秀博客链接(linux c/c++ java go php android ios 前端 j2ee windows linux 算法 ACM 深度/机器学习 AI opencv nlp)
  7. 安卓依然是华为手机首选,鸿蒙系统或许不用于手机
  8. Visual Studio、.NET Framework、VC++、C#各个版本的对应关系
  9. 关于JFace中的右键菜单Action类,ActgionGroup类,MenuManager类
  10. OCR——PaddleOCR之文字识别的学习笔记
  11. 如何通过ngnix将网站访问改为https
  12. 简易新闻网站NewsWeb-网页抓取
  13. oracle获取当前年上一年时间,Oracle获取一年中的所有日期和一个月中的所有日期...
  14. linux网卡取消混杂模式,Linux下网卡混杂模式设置和取消
  15. IPv4如何转换为IPv6?
  16. C++之 Eigen-3.4.0 全方位教程:Chapter02-矩阵篇
  17. 【MapReduce运行报错】Type mismatch inkey form map:excepted org.apache.hadoop.io.Text,recived MR.wordcount.
  18. 回溯算法求解桥本分数式
  19. java for冒号_浅谈对Java双冒号::的理解
  20. 国外大学老师用Prof.还是Dr.称呼?

热门文章

  1. python 多层包多模块_python Modules模块操作
  2. 废芯片做出来的艺术品!值得一看!
  3. PHP观察者通知机制,观察者模式-通知详解
  4. 的内怎么放_放了心脏支架能活多久?医生坦言:做到三件事,才能和正常人一样...
  5. c语言枚举入门,C语言入门之枚举与位运算(1)
  6. oracle中blob转换,BLOB转换为CLOB的函数(oracle中执行)
  7. Knight Moves
  8. web.xml上下文配置
  9. 译:Google的大规模集群管理工具Borg(二)------ Borg架构
  10. Angularjs 设置全局变量的3种方法