前面提到,函数对象是可以作为参数传递给另一函数的,这时,作为参数的函数如果在内部被执行,那么它就是个回调函数(Callback):

function writeCode(callback) {
// do something...
callback();
// ...
}
function introduceBugs() {
// ... make bugs
}
writeCode(introduceBugs);

在上面的代码里,introduceBugs就作为writeCode的参数,在writeCode函数的执行过程中被调用。因此introduceBugs就是一个回调(CallBack)函数。
下面给出一个更有实际意义的回调函数。假设我们有一个findNodes函数,它可以通过一个复杂的逻辑,在一个很大的数组中找到满足某个条件的所有结点,并返回这些结点:

var findNodes = function () {
var i = 100000, // big, heavy loop
nodes = [], // stores the result
found; // the next node found
while (i) {
i -= 1;
// complex logic here...
nodes.push(found);
}
return nodes;
};

一般来说我们都希望函数的功能单一化,所以这个函数只负责把满足某件的结点找到,并返回。然后我们写另外一个函数hide,可以把给定的一堆结点隐藏,这 个函数接受一个结点的数组作为参数,并把数组中的结点一个一个地隐藏。结合这两个函数,我们就可以完成一个组合功能,即找到一些结点,并把它们隐藏:

var hide = function (nodes) {
var i = 0, max = nodes.length;
for (; i < max; i += 1) {
nodes[i].style.display = "none";
}
}; // executing the functions
hide(findNodes());

看起来挺好。不过这种实现方法的执行效率并不高。这两个函数都需要进行一个很长的循环,则实际上,如果每找到一个满足就条件的结点,就立即把它隐藏,这样效率更高:因为只需要循环1次。为了实践这个想法,但依然把两个任务用不同的函数来实现,我们用回调的方式来做:

// refactored findNodes() to accept a callback
var findNodes = function (callback) {
var i = 100000,
nodes = [],
found; // check if callback is callable
if (typeof callback !== "function") {
callback = false;
} while (i) {
i -= 1; // complex logic here... // now callback:
if (callback) {
callback(found);
} nodes.push(found);
}
return nodes;
};

findNodes这时还是返回满足条件的所有结点,但它也接受一个回调函数,用于给每个满足条件的结点执行一些任务。这个任务就交给回调函数来声明。下面是具体的回调函数hide:

// a callback function
var hide = function (node) {
node.style.display = "none";
}; // find the nodes and hide them as you go
findNodes(hide);

当然,如果hide只服务于findNodes,有时我们不需要给它一个名字,从而把它声明为一个匿名的回调函数:

// passing an anonymous callback
findNodes(function (node) {
node.style.display = "block";
});

回调函数中的this
当回调函数中使用了this,比如,这个回调函数其实是对象myapp中的一个方法paint:

var myapp = {};
myapp.color = "green";
myapp.paint = function (node) {
node.style.color = this.color;
};

这时我们有一个全局的函数findeNodes()接受一个回调函数:

var findNodes = function (callback) {
// ...
if (typeof callback === "function") {
callback(found);
}
// ...
};

这时如果执行 findNodes(myapp.paint),并不能达到预期的结果。因为myapp.paint中的this指针在声明的时候指向的是对象中的属性, 也就是那个对象本身,但当myapp.paint作为回调函数在全局的函数findNodes时执行是,this指针在执行期间指向的就变成了全局的 this了(如果在浏览器中,就是dom对象)。
解决方法是把回调函数所属的对象也一并传递给findNodes,然后在执行回调函数时指定它所属的对象:

findNodes(myapp.paint, myapp);

所以findNodes修改为这样:

var findNodes = function (callback, callback_obj) {
//...
if (typeof callback === "function") {
callback.call(callback_obj, found);
}
// ...
};

这样看起来有点啰嗦,因为对象的名字在参数列表里出现了两次。我们也可以把这个回调函数的名字用字符串的方式传递:

findNodes("paint", myapp);

这里findNodes就相应的修改为:

var findNodes = function (callback, callback_obj) {
if (typeof callback === "string") {
callback = callback_obj[callback];
}
//...
if (typeof callback === "function") {
callback.call(callback_obj, found);
}
// ...
};

最新文章

  1. 用户 &#39;IIS APPPOOL\DefaultAppPool&#39; 登录失败。
  2. centos linux安装telnet 过程及问题(源于内部tomcat网站,外部无法访问)
  3. 查看Eclipse中的jar包的源代码:jd-gui.exe
  4. jQuery前端验证多种方式
  5. Object-C 内存管理及对象
  6. VirtualBox虚拟机安装MSDOS和MINIX2.0.0双系统
  7. Read ListViewItem content from another process z
  8. HDOJ-ACM1004(JAVA)
  9. C++类实现AVL树
  10. linux定时执行python脚本
  11. JVM指令集(指令码、助记符、功能描述)(转)
  12. 已知从BUF开始存放了10个字类型有符号数据,编程求出这10个数中的最大数和最小数(将最大数存入MAX字单元、最小数存入MIN字单元),并将其以10进制数的形式在屏幕上显示出来。
  13. G彩娱乐网一个程序员到一个销售高手的心路历程
  14. 【转载】OAuth2 流程
  15. 17.10.28&amp;29
  16. 我的CSS
  17. 爬虫协议 Tobots
  18. python 10道面试陷阱题目
  19. sklearn-数据预处理scale
  20. 如何正确地使用android中的progressdialog

热门文章

  1. CPU亲和度
  2. Java实现 LeetCode 632 最小区间(又是先序队列,官方给的是堆)
  3. Java中System的详细用法
  4. Java实现 LeetCode 30 串联所有单词的子串
  5. Tomcat的8080端口被占用无法启动Tomcat怎么办?
  6. LeetCode 76,一题教会你面试算法时的思考套路
  7. Centos 7 k8s Deployment新副本控制器
  8. Spring系列.依赖注入配置
  9. 关于领域驱动设计 DDD(Domain-Driven Design)
  10. Rectangle【思维+模拟】