浅谈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排名中的10个最著名的 JavaScript库
Apr 27 Javascript
jQuery实现动画效果的简单实例
Jan 27 Javascript
js实现iPhone界面风格的单选框和复选框按钮实例
Aug 18 Javascript
jQuery代码性能优化的10种方法
Jun 21 Javascript
AngularJS入门教程引导程序
Aug 18 Javascript
简单的渐变轮播插件
Jan 12 Javascript
js实现弹出框的拖拽效果实例代码详解
Apr 16 Javascript
详解微信小程序用定时器实现倒计时效果
Apr 30 Javascript
vue权限问题的完美解决方案
May 08 Javascript
利用百度echarts实现图表功能简单入门示例【附源码下载】
Jun 10 Javascript
vue循环数组改变点击文字的颜色
Oct 14 Javascript
vue2路由基本用法实例分析
Mar 06 Javascript
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中date()日期函数有关参数整理
2011/07/19 PHP
phpExcel导出大量数据出现内存溢出错误的解决方法
2013/02/28 PHP
修改php.ini以达到屏蔽错误信息并记录日志
2013/06/16 PHP
PHP迭代器接口Iterator用法分析
2017/12/28 PHP
Nigma vs Liquid BO3 第二场2.13
2021/03/10 DOTA
js 编程笔记 无名函数
2011/06/28 Javascript
THREE.JS入门教程(5)你应当知道的十件事
2013/01/24 Javascript
自动最大化窗口的Javascript代码
2013/05/22 Javascript
js左侧三级菜单导航实例代码
2013/09/13 Javascript
Asp.Net alert弹出提示信息的几种方法总结
2014/01/29 Javascript
js中精确计算加法和减法示例
2014/03/28 Javascript
javascript弹出页面回传值的方法
2015/01/28 Javascript
Javascript基于对象三大特性(封装性、继承性、多态性)
2016/01/04 Javascript
JavaScript Array对象详解
2016/03/01 Javascript
通过修改360抢票的刷新频率和突破8车次限制实现方法
2017/01/04 Javascript
jQuery中的$是什么意思及 $. 和 $().的区别
2018/04/20 jQuery
vuex页面刷新后数据丢失的方法
2019/01/17 Javascript
微信小程序webview实现长按点击识别二维码功能示例
2019/01/24 Javascript
vuex中store存储store.commit和store.dispatch的用法
2020/07/24 Javascript
Vue 组件复用多次自定义参数操作
2020/07/27 Javascript
python中list循环语句用法实例
2014/11/10 Python
进一步探究Python中的正则表达式
2015/04/28 Python
基于循环神经网络(RNN)的古诗生成器
2018/03/26 Python
详解用TensorFlow实现逻辑回归算法
2018/05/02 Python
在python中使用pymysql往mysql数据库中插入(insert)数据实例
2020/03/02 Python
详解pandas中iloc, loc和ix的区别和联系
2020/03/09 Python
ANINE BING官方网站:奢华的衣橱基本款和时尚永恒的单品
2019/11/26 全球购物
英国领先的高级美容和在线皮肤诊所:Face the Future
2020/06/17 全球购物
机械电子工程专业推荐信范文
2013/11/20 职场文书
优秀员工自荐书范文
2013/12/08 职场文书
季度思想汇报
2014/01/01 职场文书
收银员岗位职责
2014/02/07 职场文书
家长通知书教师评语
2014/04/17 职场文书
元旦晚会开场白
2015/05/29 职场文书
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
2022/04/13 Java/Android
JavaScript实现九宫格拖拽效果
2022/06/28 Javascript