JavaScript基础CallBack函数(015)
2014-09-10 17:36 Bryran 阅读(200) 评论(0) 编辑 收藏 举报前面提到,函数对象是可以作为参数传递给另一函数的,这时,作为参数的函数如果在内部被执行,那么它就是个回调函数(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); } // ... };