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

  1. function writeCode(callback) {
  2. // do something...
  3. callback();
  4. // ...
  5. }
  6. function introduceBugs() {
  7. // ... make bugs
  8. }
  9. writeCode(introduceBugs);

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

  1. var findNodes = function () {
  2. var i = 100000, // big, heavy loop
  3. nodes = [], // stores the result
  4. found; // the next node found
  5. while (i) {
  6. i -= 1;
  7. // complex logic here...
  8. nodes.push(found);
  9. }
  10. return nodes;
  11. };

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

  1. var hide = function (nodes) {
  2. var i = 0, max = nodes.length;
  3. for (; i < max; i += 1) {
  4. nodes[i].style.display = "none";
  5. }
  6. };
  7.  
  8. // executing the functions
  9. hide(findNodes());

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

  1. // refactored findNodes() to accept a callback
  2. var findNodes = function (callback) {
  3. var i = 100000,
  4. nodes = [],
  5. found;
  6.  
  7. // check if callback is callable
  8. if (typeof callback !== "function") {
  9. callback = false;
  10. }
  11.  
  12. while (i) {
  13. i -= 1;
  14.  
  15. // complex logic here...
  16.  
  17. // now callback:
  18. if (callback) {
  19. callback(found);
  20. }
  21.  
  22. nodes.push(found);
  23. }
  24. return nodes;
  25. };

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

  1. // a callback function
  2. var hide = function (node) {
  3. node.style.display = "none";
  4. };
  5.  
  6. // find the nodes and hide them as you go
  7. findNodes(hide);

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

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

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

  1. var myapp = {};
  2. myapp.color = "green";
  3. myapp.paint = function (node) {
  4. node.style.color = this.color;
  5. };

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

  1. var findNodes = function (callback) {
  2. // ...
  3. if (typeof callback === "function") {
  4. callback(found);
  5. }
  6. // ...
  7. };

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

  1. findNodes(myapp.paint, myapp);

所以findNodes修改为这样:

  1. var findNodes = function (callback, callback_obj) {
  2. //...
  3. if (typeof callback === "function") {
  4. callback.call(callback_obj, found);
  5. }
  6. // ...
  7. };

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

  1. findNodes("paint", myapp);

这里findNodes就相应的修改为:

  1. var findNodes = function (callback, callback_obj) {
  2. if (typeof callback === "string") {
  3. callback = callback_obj[callback];
  4. }
  5. //...
  6. if (typeof callback === "function") {
  7. callback.call(callback_obj, found);
  8. }
  9. // ...
  10. };

JavaScript基础CallBack函数(015)的更多相关文章

  1. (Frontend Newbie)JavaScript基础之函数

    函数可以说是任何一门编程语言的核心概念.要能熟练掌握JavaScript,对于函数及其相关概念的学习是非常重要的一步.本篇从函数的基本知识.执行环境与作用域.闭包.this关键字等方面简单介绍Java ...

  2. JavaScript基础学习-函数及作用域

    函数和作用域是JavaScript的重要组成部分,我们在使用JavaScript编写程序的过程中经常要用到这两部分内容,作为初学者,我经常有困惑,借助写此博文来巩固下之前学习的内容. (一)JavaS ...

  3. JavaScript 基础回顾——函数

    在JavaScript中,函数也是一种数据类型,属于 function 类型,所以使用Function关键字标识函数名.函数可以在大括号内编写代码并且被调用,作为其他函数的参数或者对象的属性值. 1. ...

  4. Javascript 基础--JS函数(三)

    一.基本概念:未完成某一个功能的代码(语句,指令)的集合. 二.函数的调用方式: 2.1.函数名(传递参数1,传递参数2)   基本语法 function 函数名(参数列表){ //代码; retur ...

  5. javascript基础(五)函数

    原文http://pij.robinqu.me/ 通过call和apply间接调用函数(改变this) call 和 apply带有多个参数,call和apply把当前函数的this指向第一个参数给定 ...

  6. javascript基础知识-函数

    1.javascript中函数有两种定义方式: 函数语句定义和表达式定义 //函数有定义 function test(){ console.log("This is a function&q ...

  7. JavaScript基础——创建函数

    JavaScript的最重要的一个部分是制作其他代码可以重用的代码.要做到这一点,你可以把代码组织成执行特定任务的函数.函数是结合在一个单一的块中,并给予一个名称的一系列代码语句.然后,你就可以通过引 ...

  8. JavaScript基础之函数与数组

     函数    函数的基本概念 为完成某一功能的程序指令(语句)的集合,称为函数.有的程序员把函数称为方法,希望大家不要被这两个名词搞晕了. 函数分为:自定义函数.系统函数(经常查看js帮助手册). j ...

  9. javascript基础知识--函数定义

    函数声明式 function funname( 参数 ){ ...执行的代码 } 声明式的函数并不会马上执行,需要我们调用才会执行:funname(); * 分号是用来分隔可执行JavaScript语 ...

随机推荐

  1. Java实现 LeetCode 541 反转字符串 II(暴力大法)

    541. 反转字符串 II 给定一个字符串和一个整数 k,你需要对从字符串开头算起的每个 2k 个字符的前k个字符进行反转.如果剩余少于 k 个字符,则将剩余的所有全部反转.如果有小于 2k 但大于或 ...

  2. Java实现 LeetCode 173 二叉搜索树迭代器

    173. 二叉搜索树迭代器 实现一个二叉搜索树迭代器.你将使用二叉搜索树的根节点初始化迭代器. 调用 next() 将返回二叉搜索树中的下一个最小的数. 示例: BSTIterator iterato ...

  3. Java实现 LeetCode 153 寻找旋转排序数组中的最小值

    153. 寻找旋转排序数组中的最小值 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 请找出其中 ...

  4. 第三届蓝桥杯JavaB组国(决)赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.数量周期 [结果填空](满分9分) 复杂现象背后的推动力,可能是极其简单的原理.科学的目标之一就是发现纷繁复杂的自然现象背后的简单法则 ...

  5. java实现哈密顿回路问题

    1 问题描述 什么是哈密顿回路? 引用自百度百科: 哈密顿图(哈密尔顿图)(英语:Hamiltonian path,或Traceable path)是一个无向图,由天文学家哈密顿提出,由指定的起点前往 ...

  6. OAuth2.0系列之基本概念和运作流程(一)

    @ 目录 一.OAuth2.0是什么? 1.1 OAuth2.0简介 1.2 OAuth2.0官方文档 二.OAuth2.0原理 2.1 OAuth2.0流程图 三. OAuth2.0的角色 四.OA ...

  7. 「从零单排canal 02」canal集群版 + admin控制台 最新搭建姿势(基于1.1.4版本)

    canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据 订阅 和 消费.应该是阿里云DTS(Data Transfer Service)的开 ...

  8. protobuf安装流程

    protobuf安装流程 环境 平台 ​ Ubuntu16.04 依赖 autoconf automake libtool curl make g++ 安装流程 在Ubuntu / Debian上,您 ...

  9. uni-app动态修改顶部导航栏标题

    动态修改顶部导航栏标题有两种方法方式一.使用自定义到导航栏,覆盖原生导航栏 缺点:自定义到导航栏性能远远不如原生导航栏,手机顶部状态栏区域会被页面内容覆盖,这是因为窗体是沉浸式的原因,即全屏可写内容: ...

  10. DockerFile构建镜像和Docker仓库

    利用commit理解镜像构成 注意: docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现 场等.但是,不要使用 docker commit 定制镜像,定制镜像应该 ...