浅谈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 相关文章推荐
js cookies实现简单统计访问次数
Nov 24 Javascript
javascript图像处理—仿射变换深度理解
Jan 16 Javascript
JavaScript之数组(Array)详解
Apr 01 Javascript
javascript中字体浮动效果的简单实例演示
Nov 18 Javascript
ES6实现的遍历目录函数示例
Apr 07 Javascript
JavaScript中splice与slice的区别
May 09 Javascript
JavaScript ES6中const、let与var的对比详解
Jun 18 Javascript
vue.js学习之UI组件开发教程
Jul 03 Javascript
浅谈mvvm-simple双向绑定简单实现
Apr 18 Javascript
javaScript产生随机数的用法小结
Apr 21 Javascript
js类的继承定义与用法分析
Jun 21 Javascript
使用JS实现简易计算器
Jun 14 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排序算法(冒泡排序,快速排序)
2012/10/09 PHP
在win系统安装配置 Memcached for PHP 5.3 图文教程
2015/03/03 PHP
解决ThinkPHP下使用上传插件Uploadify浏览器firefox报302错误的方法
2015/12/18 PHP
php生成无限栏目树
2017/03/16 PHP
ie和firefox中img对象区别的困惑
2006/12/27 Javascript
判断脚本加载是否完成的方法
2009/05/26 Javascript
javascript 选择文件夹对话框(web)
2009/07/07 Javascript
chrome下jq width()方法取值为0的解决方法
2014/05/26 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
js控制文本框输入的字符类型方法汇总
2015/06/19 Javascript
基于javascript实现单选及多选的向右和向左移动实例
2015/07/25 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
2015/09/17 Javascript
如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)
2015/10/29 Javascript
javascript 面向对象实战思想分享
2017/09/07 Javascript
JS highcharts动态柱状图原理及实现
2020/10/16 Javascript
JavaScript实现简易计算器小功能
2020/10/22 Javascript
[03:05]《我与DAC》之xiao8:DAC与BG
2018/03/27 DOTA
Python处理JSON时的值报错及编码报错的两则解决实录
2016/06/26 Python
python通过elixir包操作mysql数据库实例代码
2018/01/31 Python
tensorflow: 查看 tensor详细数值方法
2018/06/13 Python
实例分析python3实现并发访问水平切分表
2018/09/29 Python
Windows系统下PhantomJS的安装和基本用法
2018/10/21 Python
解决python中使用PYQT时中文乱码问题
2019/06/17 Python
python字符串替换第一个字符串的方法
2019/06/26 Python
python异常触发及自定义异常类解析
2019/08/06 Python
三个python爬虫项目实例代码
2019/12/28 Python
python 实时调取摄像头的示例代码
2020/11/25 Python
雅萌 (YA-MAN) :日本美容家电领域的龙头企业
2017/05/12 全球购物
Skyscanner加拿大:全球旅行搜索平台
2018/11/19 全球购物
中学生班主任评语
2014/01/30 职场文书
信用社竞聘演讲稿
2014/05/16 职场文书
反腐倡廉标语
2014/06/24 职场文书
十佳好少年事迹材料
2014/08/21 职场文书
民事申诉状范本
2015/05/20 职场文书
蓝天保卫战收官在即 :15行业将开展环保分级评价
2019/07/19 职场文书
Python采集股票数据并制作可视化柱状图
2022/04/04 Python