javascript 避免闭包引发的问题


Posted in Javascript onMarch 17, 2009

<div id="test">
<div>第一个</div>
<div>第二个</div>
<div>第三个</div>
<div>第四个</div>
</div>
<script>
function test()
{
var els = document.getElementById("test").getElementsByTagName("div");
for (var i = 0; i < els.length; i++)
{
var div = els[i];
div.onclick = function()
{
alert(div.innerHTML);
return false;
}
}
}
test();
</script>
无论我们点击哪个div,反馈的都是第4个div的内容。究其原因,在于每个div的点击事件都与test方法形成了闭包,且每个div的点击事件都共享同一个闭包作用域链。当事件被触发时,变量i所代表的下标已经指向第4个div。可以采用以下几种方式避免由于闭包引起的问题。
(1)使用this转换闭包的作用域链上下文,上例的闭包可以改写为:
for (var i = 0; i < els.length; i++)
{
var div = els[i];
div.onclick = function()
{
alert(this.innerHTML);
return false;
}
}
当点击div的事件被触发时,查找的作用域已经是“this”所指定的上下文。尽管该事件仍然处于“test”闭包内,但由于不访问或不使用闭包的上下文环境,也就不存在由于闭包作用域内变量被引用所引发的问题。
(2)使点击div的事件与for循环形成闭包,而使得for循环内的变量div不被回收。如:
//for循环内定义闭包方法
for (var i = 0; i < els.length; i++)
{
var div = els[i];
a(div);
function a(o)
{
o.onclick = function()
{
alert(o.innerHTML);
}
}
}
//for循环外定义闭包方法
for (var i = 0; i < els.length; i++)
{
var div = els[i];
a(div);
}
function a(o)
{
o.onclick = function()
{
alert(o.innerHTML);
}
}
//使用匿名方法,其原理与for循环内定义类似
for (var i = 0; i < els.length; i++)
{
var div = els[i];
(function(o)
{
o.onclick = function()
{
alert(o.innerHTML);
}
})(div);
}
通过中间方法a或者匿名方法,使for循环体与onclick事情产生闭包。
(3)控制变量的作用域,使点击div的事件所需变量与外层作用域无关。如:
for (var i = 0; i < els.length; i++)
{
(function()
{
var div = els[i];
div.onclick = function()
{
alert(div.innerHTML);
}
})();
}
内部函数自身也可能有内部函数。每次作用域链嵌套,都会增加由创建内部函数对象的执行环境所引发的新活动对象。ECMA262规范要求作用域链是临时性的,但对作用域链的长度却没有加以限制。闭包的潜规则即Function与内部定义的Function之间的相互作用域链上下文环境的关系。如果运用得当,嵌套的内部函数所拥有的潜能将超出了我们的想象力。

Javascript 相关文章推荐
浏览器解析js生成的html出现样式问题的解决方法
Apr 16 Javascript
解析JSON对象与字符串之间的相互转换
Dec 18 Javascript
直接在JS里创建JSON数据然后遍历使用
Jul 25 Javascript
js HTML5 Ajax实现文件上传进度条功能
Feb 13 Javascript
谈谈target=_new和_blank的不同之处
Oct 25 Javascript
基于vue2.0+vuex+localStorage开发的本地记事本示例
Feb 28 Javascript
关于jQuery EasyUI 中刷新Tab选项卡后一个页面变形的解决方法
Mar 02 Javascript
jQuery插件之validation插件
Mar 29 jQuery
解决Extjs下拉框不显示的问题
Jun 21 Javascript
JavaScript实现简单的树形菜单效果
Jun 23 Javascript
Vue动态获取width的方法
Aug 22 Javascript
vue路由结构可设一层方便动态添加路由操作
Aug 31 Javascript
用JavaScript编写COM组件的步骤
Mar 17 #Javascript
IE6与IE7中,innerHTML获取param的区别
Mar 15 #Javascript
InnerHtml和InnerText的区别分析
Mar 13 #Javascript
JavaScript 快捷键设置实现代码
Mar 13 #Javascript
JavaScript 事件属性绑定带参数的函数
Mar 13 #Javascript
自动完成JS类(纯JS, Ajax模式)
Mar 12 #Javascript
动态添加js事件实现代码
Mar 12 #Javascript
You might like
php数据入库前清理 注意php intval与mysql的int取值范围不同
2010/12/12 PHP
PHP5函数小全(分享)
2013/06/06 PHP
PHP 转义使用详解
2013/07/15 PHP
php带抄送和密件抄送的邮件发送方法
2015/03/20 PHP
php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比
2015/04/14 PHP
微信公众平台实现获取用户OpenID的方法
2015/04/15 PHP
PHP实现XML与数据格式进行转换类实例
2015/07/29 PHP
初识JQuery 实例一(first)
2011/03/16 Javascript
基于jquery的$.ajax async使用
2011/10/19 Javascript
setTimeout的延时为0时多个浏览器的区别
2012/05/23 Javascript
javascript实现TreeView 无刷新展开的实例代码
2013/07/13 Javascript
js中的scroll和offset 使用比较的实例与分析
2013/09/29 Javascript
javacript使用break内层跳出外层循环分析
2015/01/12 Javascript
JavaScript中使用concat()方法拼接字符串的教程
2015/06/06 Javascript
基于BootStrap Metronic开发框架经验小结【七】数据的导入、导出及附件的查看处理
2016/05/12 Javascript
JS类的定义与使用方法深入探索
2016/11/26 Javascript
详解Angular2 之 结构型指令
2017/06/21 Javascript
JS实现li标签的删除
2019/04/12 Javascript
解决vue 给window添加和移除resize事件遇到的坑
2020/07/21 Javascript
[53:36]Liquid vs VP Supermajor决赛 BO 第三场 6.10
2018/07/05 DOTA
Python入门篇之对象类型
2014/10/17 Python
在Python的struct模块中进行数据格式转换的方法
2015/06/17 Python
Python的Flask框架中使用Flask-SQLAlchemy管理数据库的教程
2016/06/14 Python
Python实现向服务器请求压缩数据及解压缩数据的方法示例
2017/06/09 Python
python网络爬虫学习笔记(1)
2018/04/09 Python
PyCharm安装第三方库如Requests的图文教程
2018/05/18 Python
Python OpenCV实现测量图片物体宽度
2020/05/27 Python
CSS3近阶段篇之酷炫的3D旋转透视
2016/04/28 HTML / CSS
高清屏下canvas重置尺寸引发的问题的解决
2019/10/14 HTML / CSS
adidas菲律宾官网:adidas PH
2020/02/07 全球购物
介绍一下MYSQL常用的优化技巧
2012/10/25 面试题
彩色的非洲教学反思
2014/02/18 职场文书
勤俭节约演讲稿
2014/05/08 职场文书
领导班子三严三实对照检查材料
2014/09/25 职场文书
教师节校长致辞
2015/07/31 职场文书
Python办公自动化解决world文件批量转换
2021/09/15 Python