上班无聊,先废话几句。
我是个很懒的人,博客几乎不更新,代码也不想撸,有活干活,没活刷豆瓣玩农场。
技术学习进入瓶颈。不知从何提高,自己也没什么动力。现在就是上班无聊,为了防止脑子生锈老年痴呆,顺便看看文章捣鼓捣鼓啦。
作为一个妹纸,我的远大理想永远是怎么把自己打扮的更好看 = =
回调 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) })() }
至于闭包是如何做到的,需要用更长的篇幅去讨论了。这里暂不深入。