函数式编程初探之回调 - Callback

上班无聊,先废话几句。

我是个很懒的人,博客几乎不更新,代码也不想撸,有活干活,没活刷豆瓣玩农场。
技术学习进入瓶颈。不知从何提高,自己也没什么动力。现在就是上班无聊,为了防止脑子生锈老年痴呆,顺便看看文章捣鼓捣鼓啦。
作为一个妹纸,我的远大理想永远是怎么把自己打扮的更好看 = =
 
回调 Callbak
这个东西大家都听说过,最初我也很迷茫,只是听说不知其为何物。
说白了,就是把函数作为参数嘛!关回调啥事呀。回调只是它的应用所在。
经典的Jquery的Ajax我不想谈,在这里谈谈JS原生的Array的Map方法。
 
代码是这个样子 ↓↓ 
array.map(callback,[ thisObject]);
[].map(function(value, index, array) {
    // ...
});

 

这是Array对象的原型方法,它有两个参数,第一个参数是callback,第二个参数为this关键字的绑定,可省略。
map是顾名思义呢是一个映射函数,对数组里的每个对象依次执行Callback,返回一个新的数组。
文字不是很明白,看实例。
 
var misa = [1, 2, 3],
misamisa = misa.map(function(value, index) {
    return value * value
}}
我觉得这个例子有点糟。(最近有点傻不会写例子了 T^T 凑合着)
对misa数组里的每个对象,执行value * value,也就是返回平方。得到的结果就是一个新的数组[1, 4, 9]
function(value, index) 这个匿名函数,在misa.map 方法的生命周期里执行。这就是传说中的回调。
 
总有人搞不清回调函数里的参数是哪来的。
比如$.ajax里的function(data) ,  addEventListener里的event。经常有人问我这样的问题。
一开始我也是这样啦。我们自己来写一个map方法来有助于更好的理解吧!
  var a = [1, 2, 3]

  Array.prototype.mymap = function (callback) {
    var length = this.length,
    b = new Array;
    for(var i = 0; i < length; i++) {
      b[i] = callback(this[i], i)
    }
    return b;
  }

  var b = a.mymap(function(val) {
    return val * val
  })
mymap模拟实现了map方法。callback里的参数,就是这么传过来的。跟命名完全没有关系,跟参数的顺序才有关系。
这里我没有用到第二个参数i,所以在调用的时候没有写。
 
当然,你也可以把callback提取出来写在外面。写成这样 ↓↓
var callback = function(val, index) {
    console.log(index)
    return val * val
  }
  var b = a.mymap(callback)

下面来讲一讲在实际的应用中,新手容易犯的错误。比如JS的事件监听。一般的定法是这样

  document.getElementById('btn').addEventListener('click', function(event) { 
    console.log(event) 
  }, false)

如果想把第二个参数抽出来,可以这样写

function clickBtn(val) { 
    console.log(val) 
  } 
document.getElementById(
'btn').addEventListener('click', clickBtn, false)

 而不是这样 ↓↓

/* 错误代码 */
document.getElementById('btn').addEventListener('click', clickBtn(event), false)
上面代码犯了什么错误呢,就是没理解clickBtn是作为addEventListener方法的一个参数而存在的。
clickBtn的参数,是在addEventListener的执行过程中传入的。上面的写法,其实是把clickBtn(event)执行后的结果做为参数传入。
 
还有一种常见的代码
  var img = document.getElementsByTagName('img') 
  for(var i = 0; i < img.length; i++) { 
      img[i].addEventListener('click', function() { 
        alert(i + 1) 
      }, false) 
  }
假设页面上有十张图片,我们的预期结果是点第一张弹出1,第二张弹出2……而实际结果是每张都alert 11。即i的最终值。
为什么会这样。因为addEventListener并没有记住i,也没有理由记住i。i作为循环变量的生命周期只在for循环内部,addEventListener为IMG标签绑定点击事件的监听。而真正执行点击的时候,函数处在全局环境。因为i始终为循环结束后的值 11。
 
那么如何把i带入到addEventListener内部呢?
我们可以用闭包。
  for(var i = 0; i < img.length; i++) { 
      (function() { 
        var _i= i; 
        img[i].addEventListener('click', function() { 
          alert(_i + 1) 
        }, false) 
      })() 
  }
至于闭包是如何做到的,需要用更长的篇幅去讨论了。这里暂不深入。
posted @ 2014-05-15 17:51  misa  阅读(489)  评论(1)    收藏  举报