Javascript闭包演示【转】
文章出自http://www.cnblogs.com/snandy/archive/2011/03/01/1967628.html
有个网友问了个问题,如下的html,为什么点击所有的段落p输出都是5,而不是alert出对应的0,1,2,3,4。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!DOCTYPE HTML> <html> <head> <meta charset= "utf-8" /> <title>闭包演示</title> <style type= "text/css" > p {background:gold;} </style> <script type= "text/javascript" > function init() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = function () { alert(i); } } } </script> </head> <body onload= "init();" > <p>产品 0</p> <p>产品 1</p> <p>产品 2</p> <p>产品 3</p> <p>产品 4</p> </body> </html> |
以上场景是初学者经常碰到的。即获取HTML元素集合,循环给元素添加事件。在事件响应函数中(event handler)获取对应的索引。但每次获取的都是最后一次循环的索引。
原因是初学者并未理解JavaScript的闭包特性。通过element.onclick=function(){alert(i);}方式给元素添加点击事件。响应函数function(){alert(i);}中的 i 并非每次循环时对应的 i(如0,1,2,3,4)而是循环后最后 i 的值5。 或者说循环时响应函数内并未能保存对应的值 i,而是最后一次i++的值5。
了解了原因,摸索出了很多解决办法(纯粹是兴趣)。最先想到的前两种
1、将变量 i 保存给在每个段落对象(p)上
1
2
3
4
5
6
7
8
9
|
function init1() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { pAry[i].i = i; pAry[i].onclick = function () { alert( this .i); } } } |
2、将变量 i 保存在匿名函数自身
1
2
3
4
5
6
7
8
|
function init2() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { (pAry[i].onclick = function () { alert(arguments.callee.i); }).i = i; } } |
后又想到了三种
3、加一层闭包,i 以函数参数形式传递给内层函数
1
2
3
4
5
6
7
8
9
10
|
function init3() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { ( function (arg){ pAry[i].onclick = function () { alert(arg); }; })(i); //调用时参数 } } |
4、加一层闭包,i 以局部变量形式传递给内层函数
1
2
3
4
5
6
7
8
9
10
11
|
function init4() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { ( function () { var temp = i; //调用时局部变量 pAry[i].onclick = function () { alert(temp); } })(); } } |
5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)
1
2
3
4
5
6
7
8
9
10
|
function init5() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = function (arg) { return function () { //返回一个函数 alert(arg); } }(i); } } |
后又发现了两种
6、用Function实现,实际上每产生一个函数实例就会产生一个闭包
1
2
3
4
5
6
|
function init6() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = new Function( "alert(" + i + ");" ); //new一次就产生一个函数实例 } } |
7、用Function实现,注意与6的区别
1
2
3
4
5
6
|
function init7() { var pAry = document.getElementsByTagName( "p" ); for ( var i=0; i<pAry.length; i++ ) { pAry[i].onclick = Function( 'alert(' +i+ ')' ); } } |
Javascript闭包演示【转】的更多相关文章
- JavaScript闭包演示
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title&g ...
- js闭包演示
有个网友问了个问题,如下的html,为什么每次输出都是5 <html > <head> <meta http-equiv="Content-Type" ...
- JavaScript闭包模型
JavaScript闭包模型 ----- [原创翻译]2016-09-01 09:32:22 < 一> 闭包并不神秘 本文利用JavaScript代码来阐述闭包,目的是为了使普通 ...
- JavaScript闭包示例
在下面的例子中,为什么点击所有的段落p输出都是5,而不是alert出对应的0,1,2,3,4. <html> <head> <meta charset="utf ...
- javascript闭包传参和事件的循环绑定
今天看到一个javascript的题目,按常理循环绑定事件,但是得到的结果却不是想要的. <a href="#">text</a><br>< ...
- JavaScript 闭包环境非常奇特 - 相当于类与实例的关系?!
JavaScript 闭包环境非常奇特 - 相当于类与实例的关系?! 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一 ...
- 让你能看懂的 JavaScript 闭包
让你能看懂的 JavaScript 闭包 没有废话,直入主题,先看一段代码: var counter = (function() { var x = 1; return function() { re ...
- Javascript闭包入门(译文)
前言 总括 :这篇文章使用有效的javascript代码向程序员们解释了闭包,大牛和功能型程序员请自行忽略. 译者 :文章写在2006年,可直到翻译的21小时之前作者还在完善这篇文章,在Stackov ...
- javascript闭包中循环问题
如下的html,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html > <head> <meta http-equiv=&quo ...
随机推荐
- 执行上下文--变量、函数、this
原文地址:https://www.xingkongbj.com/blog/js/execution-context.html JavaScript 中的执行上下文和调用栈 ES6 变量作用域与提升:变 ...
- window.moveTo(),window.moveBy()不生效
window.moveTo()和window.moveBy的菜鸟教程介绍: moveTo() 方法可把窗口的左上角移动到一个指定的坐标. window.moveTo(x,y) moveBy() 方法可 ...
- JS DOM 1
接触JS也有快一个月了,现在来总结一下看过的书,一本本总结,之后再融会贯通,也许更有助于学习.废话不多说,现在看的是<JavaScript DOM编程艺术>,该书挺薄的,不太会望而生畏,( ...
- 常用的JavaScript设计模式(二)Factory(工厂)模式
Factory通过提供一个通用的接口来创建对象,同时,我们还可以指定我们想要创建的对象实例的类型. 假设现在有一个汽车工厂VehicleFactory,支持创建Car和Truck类型的对象实例,现在需 ...
- UEditor代码实现高亮显示
在公司开发一个论坛系统,由于用的是UEditor(百度编辑器),单独使用的话,里面的代码不会高亮,网上找了很多,最后决定使用 highlight.js 实现代码高亮显示.效果如下: 这个是我修改其他的 ...
- thinkphp5 部署到iis服务器url重写
thinkphp部署到iis服务器配置url重写的解决方法: 1.下载 url rewrite.下载地址:https://www.iis.net/downloads/microsoft/url-rew ...
- Currency Helper
using System; using Microsoft.Xrm.Sdk; using Microsoft.Crm.Sdk.Messages; /// <summary> /// 货币 ...
- 北京Uber优步司机奖励政策(2月16日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 北京Uber优步司机奖励政策(1月9日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 北京Uber优步司机奖励政策(9月21日~9月27日)
用户组:优步北京人民优步A组(适用于9月21日-9月27日) 滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不 ...