前面提到,函数对象是可以作为参数传递给另一函数的,这时,作为参数的函数如果在内部被执行,那么它就是个回调函数(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);
}
// ...
};

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 463 岛屿的周长

    463. 岛屿的周长 给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域. 网格中的格子水平和垂直方向相连(对角线方向不相连).整个网格被水完全包围,但其中恰好有一个岛屿(或者 ...

  2. Java实现 LeetCode 65 有效数字

    65. 有效数字 验证给定的字符串是否可以解释为十进制数字. 例如: "0" => true " 0.1 " => true "abc&q ...

  3. Java实现LeetCode_0013_RomanToInteger

    package javaLeetCode.primary; import java.util.HashMap; import java.util.Map; import java.util.Scann ...

  4. Java实现币值最大化问题

    1 问题描述 给定一排n个硬币,其面值均为正整数c1,c2,-,cn,这些整数并不一定两两不同.请问如何选择硬币,使得在其原始位置互不相邻的条件下,所选硬币的总金额最大. 2 解决方案 2.1 动态规 ...

  5. Java实现第九届蓝桥杯小朋友崇拜圈

    小朋友崇拜圈 题目描述 班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己). 在一个游戏中,需要小朋友坐一个圈, 每个小朋友都有自己最崇拜的小朋友在他的右手边. 求满足条件的圈最大多少人 ...

  6. (五)SQLMap工具检测SQL注入漏洞、获取数据库中的数据

    目录结构 一.判断被测url的参数是否存在注入点 二.获取数据库系统的所有数据库名称(暴库) 三.获取Web应用当前所连接的数据库 四.获取Web应用当前所操作的DBMS用户 五.列出数据库中的所有用 ...

  7. 注解实现SpringCache自定义失效时间

    注解实现SpringCache自定义失效时间 SpringCache是一个很方便的缓存框架,但是官方提供的缓存的配置只有全局的缓存失效时间,没有针对某个命名空间做配置,因为工作上业务的关系需要针对某一 ...

  8. Python Opencv-contrib Camshift&kalman卡尔曼滤波&CSRT算法 目标跟踪实现

    本次课题实现目标跟踪一共用到了三个算法,分别是Camshift.Kalman.CSRT,基于Python语言的Tkinter模块实现GUI与接口设计,项目一共包含三个文件: main.py: # co ...

  9. 【Spring Cloud 系列】 二、Spring Cloud Eureka 的第一印象

    Eureka : 翻译翻译,找到了!(惊讶语气) Spring CLoud 中的 Spring Cloud Eureka,用于 分布式项目中的服务治理.是对Netflix 套件中的Eureka 的二次 ...

  10. Rectangle【思维+模拟】

    Rectangle 题目链接(点击) frog has a piece of paper divided into nn rows and mm columns. Today, she would l ...