浅谈JavaScript之事件绑定


Posted in Javascript onJuly 08, 2013

其实没有什么新的知识点,只是为了方便其他有需要的朋友们翻阅,对自己而言也算是一个积累,所以只能算是闲谈 JavaScript,老鸟们可以尽情飘过。
在进入正题之前,先提个问题热热身吧。
现在有如下 HTML 结构:

<div id="wrap">
 <input type="button" value="按钮一" />
 <input type="button" value="按钮二" />
 <input type="button" value="按钮三" />
 <input type="button" value="按钮四" />
 <input type="button" value="按钮五" />
</div>

以及如下 JavaScript 代码:
var wrap = document.getElementById('wrap'), 
    inputs = wrap.getElementsByTagName('input'); for (var i = 0, l = inputs.length; i < l; i++) { 
    inputs[i].onclick = function () { 
        alert(i); 
    } 
}

请问,这样执行的结果是什么?
/***************************分割线***************************/
如果你的回答是“点击按钮时, alert 当前按钮的索引值 i”,那你就中了我的圈套了。大家不妨试试,无论你点击哪个按钮,它都会alert(5)。

这个看似理所当然的结果为什么会和实际情况不同呢?其实也是很好理解的。
因为 onclick 只是事件绑定,而不是执行,当我们执行 onclick 事件的时候,这时的 i 已经是循环以后的值了,照这样看,每个按钮都alert(5) 也就不足为奇了。

那么,如果我们要怎么实现“点击按钮时,alert 当前按钮的索引值 i”呢?这里就要用到 JavaScript 中暗藏玄机的一个概念“闭包”。我们可以用闭包的方式改写以上 JS,把 for 循环中的 i 值保存在内存中,代码如下:

var wrap = document.getElementById('wrap'), 
    inputs = wrap.getElementsByTagName('input'); for (var i = 0, l = inputs.length; i < l; i++) { 
    (function (cur) { 
        inputs[cur].onclick = function () { 
            alert(cur); 
        } 
    })(i) 
}

再试试效果?确实能 alert 出相应的索引值了,不过至此为止还只是开胃菜,正题才刚刚开始!
以上的方法,我们是通过循环 + 闭包给 button 按钮上绑定事件,我们知道,在 JavaScript 中函数也是对象,对象就会占用内存,现在的例子中只有 5 个按钮,或许你会认为这样的性能开销可以忽略不计,但是如果当我们有 50个,甚至 500 个按钮的时候,IE 已经哭了,当有更多其他性能隐患并发时,所有的浏览器都哭了。

回到刚才的例子,我们可以用“事件委托”的方法来解决这个因绑定事件随着按钮增加而可能导致的性能问题。原理很简单,利用 Javascript 的事件冒泡,我们可以把事件的绑定从按钮移到它们的父级元素上,不管按钮有多少,它们只有一个共同的父级元素,那样我们只需要绑定一次事件就可以了。
代码如下:

var wrap = document.getElementById('wrap'), 
    inputs = wrap.getElementsByTagName('input'); wrap.onclick = function (ev) { 
    var ev = ev || window.event, 
    target = ev.target || ev.srcElement; 
    for (var i = 0, l = inputs.length; i < l; i++) { 
        if (inputs[i] === target) { 
            alert(i) 
        } 
    } 
}

至此,正餐完毕,我们还可以再深入一下,来些餐后甜点。
除了在性能上,事件委托比闭包的事件绑定更有优势以外,事件委托还无需顾及子元素(即被绑定事件的元素)的数量。比如,我们在 onclick 事件绑定以后,增加一个按钮:
var newInput = document.createElement('input'); 
newInput.setAttribute('type', 'button'); 
newInput.setAttribute('value', '按钮六'); 
wrap.appendChild(newInput);

同样在最后加了这段代码的闭包方式和事件委托方式,我们可以看到,闭包实现的事件绑定中点击“按钮六”毫无效果,但是在事件委托中实现的事件绑定点击“按钮六”则会有 alert。相反,如果我们要删除一个按钮,闭包的方式仍会在内存中保存已删除按钮的 onclick 事件(除非手动设为 null),事件委托则不会对内存造成多余的负担,就为这个原因,我们也应该多加利用事件委托的方式来绑定同一层级的多个元素。
Javascript 相关文章推荐
该如何加载google-analytics(或其他第三方)的JS
May 13 Javascript
jquery下json数组的操作实现代码
Aug 09 Javascript
编写自己的jQuery插件简单实现代码
Apr 19 Javascript
JavaScript中判断整字类型最简洁的实现方法
Nov 08 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
Mar 06 Javascript
JS随机排序数组实现方法分析
Oct 11 Javascript
微信小程序学习笔记之函数定义、页面渲染图文详解
Mar 28 Javascript
详解如何写出一个利于扩展的vue路由配置
May 16 Javascript
浅谈Vue的响应式原理
May 30 Javascript
vue+elementUI实现图片上传功能
Aug 20 Javascript
layer弹出层自适应高度,垂直水平居中的实现
Sep 16 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
Jun 24 jQuery
JS Map 和 List 的简单实现代码
Jul 08 #Javascript
利用JS实现浏览器的title闪烁
Jul 08 #Javascript
利用js实现遮罩以及弹出可移动登录窗口
Jul 08 #Javascript
使用jquery实现简单的ajax
Jul 08 #Javascript
从数据结构的角度分析 for each in 比 for in 快的多
Jul 07 #Javascript
JavaScript 上万关键字瞬间匹配实现代码
Jul 07 #Javascript
20行代码实现的一个CSS覆盖率测试脚本
Jul 07 #Javascript
You might like
php中Ctype函数用法详解
2014/12/09 PHP
php实现SAE上使用storage上传与下载文件的方法
2015/06/29 PHP
基于PHP实现等比压缩图片大小
2016/03/04 PHP
php实现支付宝当面付(扫码支付)功能
2018/05/30 PHP
laravel实现Auth认证,登录、注册后的页面回跳方法
2019/09/30 PHP
基于jQuery的仿flash的广告轮播
2010/11/05 Javascript
Jquery中getJSON在asp.net中的使用说明
2011/03/10 Javascript
禁止空格提交表单的js代码
2013/11/17 Javascript
jquery获取复选框被选中的值
2014/03/22 Javascript
javascript 获取HTML DOM父、子、临近节点
2014/06/16 Javascript
jQuery 处理页面的事件详解
2015/01/20 Javascript
初步认识JavaScript函数库jQuery
2015/06/18 Javascript
JavaScript中对JSON对象的基本操作示例
2016/05/21 Javascript
AngularJS自定义控件实例详解
2016/12/13 Javascript
利用Vue.js实现checkbox的全选反选效果
2017/01/18 Javascript
JS中的多态实例详解
2017/10/15 Javascript
浅谈Node.js 中间件模式
2018/06/12 Javascript
vue debug 二种方法
2018/09/16 Javascript
jquery实现动态创建form并提交的方法示例
2019/05/27 jQuery
Vue 实现v-for循环的时候更改 class的样式名称
2020/07/17 Javascript
逐行分析鸿蒙系统的 JavaScript 框架(推荐)
2020/09/17 Javascript
[01:05:59]Mineski vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.22
2019/09/05 DOTA
Python实现发送email的几种常用方法
2014/08/18 Python
分分钟入门python语言
2018/03/20 Python
Python 旋转打印各种矩形的方法
2019/07/09 Python
python GUI库图形界面开发之PyQt5打印控件QPrinter详细使用方法与实例
2020/02/28 Python
Scrapy基于scrapy_redis实现分布式爬虫部署的示例
2020/09/29 Python
CSS3 倾斜的网页图片库实例教程
2009/11/14 HTML / CSS
Hotels.com爱尔兰:全球酒店预订
2017/02/24 全球购物
意大利运动服减价商店:ScontoSport
2020/03/10 全球购物
个人素质的自我评价分享
2013/12/16 职场文书
小学生新学期寄语
2014/01/19 职场文书
读书演讲主持词
2014/03/18 职场文书
颐和园的导游词
2015/01/30 职场文书
美容院管理规章制度
2015/08/05 职场文书
科学家研发出新型速效酶,可在 24 小时内降解塑料制品
2022/04/29 数码科技