JavaScript的闭包特性如何给循环中的对象添加事件(一)
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件。在事件响应函数中(event handler)获取对应的索引。但每次获取的都是最后一次循环的索引。原因是初学者并未理解JavaScript的闭包特性。
1. <!DOCTYPE HTML>
2. <html>
3. <head>
4. <meta charset="utf-8" />
5. <title>闭包演示</title>
6. <style type="text/css">
7. p {background:gold;}
8. </style>
9. <script type="text/javascript">
10.function init() {
11. var pAry = document.getElementsByTagName("p");
12. for( var i=0; i<pAry.length; i++ ) {
13. pAry[i].onclick = function() {
14. alert(i);
15. }
16. }
17.}
18.</script>
19.</head>
20.<body οnlοad="init();">
21.<p>产品 0</p>
22.<p>产品 1</p>
23.<p>产品 2</p>
24.<p>产品 3</p>
25.<p>产品 4</p>
26.</body>
27.</html>
以上场景是初学者经常碰到的。即获取HTML元素集合,循环给元素添加事件。在事件响应函数中(event handler)获取对应的索引。但每次获取的都是最后一次循环的索引。
原因是初学者并未理解JavaScript的闭包特性。通过element.οnclick=function(){alert(i);}方式给元 素添加点击事件。响应函数function(){alert(i);}中的 i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值 i,而是最后一次i++的值5。
了解了原因,下面就由几种方式可与解决:
1、将变量 i 保存给在每个段落对象(p)上
1. function init1() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. pAry[i].i = i;
5. pAry[i].onclick = function() {
6. alert(this.i);
7. }
8. }
9. }
2、将变量 i 保存在匿名函数自身
1. function init2() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. (pAry[i].onclick = function() {
5. alert(arguments.callee.i);
6. }).i = i;
7. }
8. }
3、加一层闭包,i 以函数参数形式传递给内层函数
1. function init3() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. (function(arg){
5. pAry[i].onclick = function() {
6. alert(arg);
7. };
8. })(i);//调用时参数
9. }
10.}
4、加一层闭包,i 以局部变量形式传递给内层函数
1. function init4() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. (function () {
5. var temp = i;//调用时局部变量
6. pAry[i].onclick = function() {
7. alert(temp);
8. }
9. })();
10. }
11.}
5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
1. function init5() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. pAry[i].onclick = function(arg) {
5. return function() {//返回一个函数
6. alert(arg);
7. }
8. }(i);
9. }
10.}
6、用Function实现,实际上每产生一个函数实例就会产生一个闭包
1. function init6() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. pAry[i].onclick = new Function("alert(" + i + ");");//new一次就产生一个函数实例
5. }
6. }
7、用Function实现,注意与6的区别
1. function init7() {
2. var pAry = document.getElementsByTagName("p");
3. for( var i=0; i<pAry.length; i++ ) {
4. pAry[i].onclick = Function('alert('+i+')');
5. }
6. }
JavaScript的闭包特性如何给循环中的对象添加事件(一)的更多相关文章
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)
原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...
- 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 给ul中的li添加事件的多种方法
给ul中的li添加事件的多种方法 这是一个常见,而且典型的前端面试题 <ul> <li>11111</li> <li>22222</li> ...
- React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路
React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路 这几天在忙着把自己做的项目中的类组件转化为功能相同的函数组件,首先先贴一份该组件类组件的关 ...
- JavaScript的闭包特性
闭包是一个比较抽象的概念,尤其是对js新手来说.在这里,我就我个人的理解j简单谈一下: 闭包:官方解释是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部 ...
- JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
文章目录 1.对象的简介 2.对象的基本操作 2.1 代码 2.2 测试结果 3.属性和属性值 3.1 代码 3.2 测试结果 4.对象的方法 4.1 代码 4.2 测试结果 5.对象字面量 5.1 ...
- PHP 循环中临时对象不销毁,会保存到一下循环,这是什么坑。。
在C++中,根本存在这种问题,一个对象或结构体在循环中声明赋值了,再一次循环就自动清空.但是在PHP中这个$monthData在下一次循环却不会重新赋值,而是保留了上一次赋值的值,这样的下一次save ...
- JavaScript中给对象添加方法
在JavaScript中,我们经常要给已定义的对象添加一些方法,如下: function circle(w,h){ this.width=w; this.height=h; ...
随机推荐
- bug调试宝典
bug调试技巧 宝典之一 : 坚信一个原则,程序不会说谎,一定是有原因的 多数的错误表现看起来莫明奇妙,甚至不可思议 但当我们找到问题后会发现:其实问题的根源是如此简单.如此的合乎道理. 这就要求我们 ...
- 【面试突击】-RabbitMQ常见面试题(三)
1.什么是RabbitMQ?为什么使用RabbitMQ? 答:RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的,消息中间件: 可以用它来:解耦.异步.削峰. 2.RabbitMQ有 ...
- uni-app学习(三)好用的插件1
1. uni-app学习(三) 1.1. async/await使用 表示异步处理,可使用then函数继续操作,返回的是Promise async function timeout() { retur ...
- 关于OC中直接打印结构体(CGRectCGSize、CGPoint、UIOffset)等数据类型
关于OC直接打印结构体,点(CGRect,CGSize,CGPoint,UIOffset)等数据类型,我们完全可以把其转换为OC对象来进项打印调试,而不必对结构体中的成员变量进行打印.就好比我们可以使 ...
- hadoop mapreduce求解有序TopN
利用hadoop的map和reduce排序特性实现对数据排序取TopN条数据. 代码参考:https://github.com/asker124143222/wordcount 1.样本数据,假设是订 ...
- 五分钟搞懂什么是B-树(全程图解)【转】
前戏 我们大家都知道动态查找树能够提高查找效率,比如:二叉查找树,平衡二叉查找树,红黑树.他们查找效率的时间复杂度O(log2n),跟树的深度有关系,那么怎么样才能提高效率呢?当然最快捷的方式就是减少 ...
- [Go] 分页计算页码的主要逻辑
当使用imap进行读取邮件体的时候,有个函数可以根据传入的开始和结束索引来一次读取多条邮件内容主要逻辑类似这样,从1开始, 1,10 11,20 21,30 或者 1,31 32,63 ...
- vue--实现跑马灯效果
<div id="app"> <input type="button" value="开始" @click="l ...
- Note | Ubuntu
目录 0. 教程 1. 安装 2. 系统 0. 教程 <Linux就该这么学>:https://www.cnblogs.com/RyanXing/p/9462850.html 1. 安装 ...
- awk、sed、grep更适合的方向
awk.sed.grep更适合的方向: grep 更适合单纯的查找或匹配文本 sed 更适合编辑匹配到的文本 awk 更适合格式化文本,对文本进行较复杂格式处理 关于awk内建变量个人见解,简单易懂 ...