js循环绑定事件javascript
在js中,用循环来为一个元素队列的元素绑定事件,是一个常见的问题。java
一般进入误区的新人,都会理想固然地这么写代码:浏览器
(假设元素队列为o,默认使用jQuery)闭包
//error method
var o =$('.blockHead'); for(var i=0; i<o.length; i++){ o[i].onclick = function(){ alert(i); } }
固然这种状况下,你会发现每一个元素点击运行时,显示的 i值 都是 o.length-1;异步
由于js的函数是调用时触发,绑定事件的时候i值并无被传入执行函数里。函数
做为异步监听的事件,点击事件发生的时候,循环已经结束,此时的 i值 为[o.length-1], 触发事件传递的参数天然是同一个最大值,而不是预期不一样元素传不一样值。性能
解决办法思路:将绑定事件过程当中获得的i值,在执行函数域里保存起来;调用时天然就获得相应的结果。this
方法一: 使用闭包函数存储i值spa
var o = $('.blockHead'); for(var i=0; i<o.length; i++){ o[i].onclick = (function closure(ii){ //var ii; //we save ii in this scope return function(){ alert(ii); } })(i); }
如上,colsure是一个闭包函数(closure函数名可省去,做匿名闭包函数),声明后当即执行,传递了i值,因而在它的函数域里保存了i值(arguments参数列表里);代理
函数的返回结果是事件处理函数,其参数ii就是colsure里保存的ii值,也就是循环时就传递的i值。
ps:方法一是很是常见的处理该问题的解决方法;在寻找解决方案的过程里,我发现了另外一个写法,以下。
方法二: 将事件绑定的代码写在一个外围函数里
var o = $('.blockHead'); for(var i=0; i<o.length; i++){ attach(i,o[i]); function attach(ii,o){ o.onclick = function(){ alert(ii); }; } } //或者 直接在声明函数后马上执行 var o = $('.blockHead'); for(var i=0; i<o.length; i++){ (function attach(ii,o){ o.onclick = function(){ alert(ii); }; })(i,o[i]); }
//在函数域范围内可访问外层函数的变量,用一个生存与当即函数的变量来存贮i,因而能够写成酱紫 var o = $('.blockHead'); for(var i=0; i<o.length; i++){ (function (){ var p = i; o[i].onclick = function(){ alert(p); }; })(); }
一样的道理,在attach的函数域里,onclick事件获得的ii值已是执行循环便获取的的i,而外部的i执行完循环后的结果是什么已经跟内部没有关系了。
稍许比方法一麻烦的是,参数须要多传递一个元素的引用。
最后一个方法显然是最简便明朗的。
js的事件代理机制
让咱们追溯到问题更深刻的部分,即什么场景会出现[事件循环绑定]的要求?一个父级元素的子级元素队列元素绑定事件,除了一个一个子级元素地去绑定有更好的解决方案么?
真巧,js有这么一种机制,叫 事件代理/委托(delegate),基于浏览器事件处理的冒泡机制,用一个事件处理程序能够管理某一类型的全部事件。
当须要多个元素添加事件的时候,能够经过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。
使用代理的好处:减小事件处理程序的数量,可以很好提升js性能;
延迟指定对DOM元素的处理程序,使得交互时间缩短。