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 相关文章推荐
jquery 学习笔记一
Apr 07 Javascript
Jquery提交表单 Form.js官方插件介绍
Mar 01 Javascript
jquery中使用$(#form).submit()重写提交表单无效原因分析及解决
Mar 25 Javascript
JS实现点击颜色块切换指定区域背景颜色的方法
Feb 25 Javascript
js实现数组冒泡排序、快速排序原理
Mar 08 Javascript
js+css3实现旋转效果
Jan 20 Javascript
vue双向绑定简要分析
Mar 23 Javascript
vue.js实现数据动态响应 Vue.set的简单应用
Jun 15 Javascript
基于vue-cli配置lib-flexible + rem实现移动端自适应
Dec 26 Javascript
Vue中的slot使用插槽分发内容的方法
Mar 01 Javascript
jquery实现的简单轮播图功能【适合新手】
Aug 17 jQuery
Vue2.0生命周期的理解
Aug 20 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实现文件下载更能介绍
2012/11/23 PHP
ThinkPHP中url隐藏入口文件后接收alipay传值的方法
2014/12/09 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
Input 特殊事件onpopertychange和oninput
2009/06/17 Javascript
FF IE兼容性的修改小结
2009/09/02 Javascript
使用Javascript接收get传递的值的代码
2011/11/30 Javascript
javascript动态加载三
2012/08/22 Javascript
js鼠标滑过弹出层的定位IE6bug解决办法
2012/12/26 Javascript
jquery解决图片路径不存在执行替换路径
2013/02/06 Javascript
jQuery中[attribute^=value]选择器用法实例
2014/12/31 Javascript
js读取csv文件并使用json显示出来
2015/01/09 Javascript
Javascript对象Clone实例分析
2015/06/09 Javascript
js变形金刚文字特效代码分享
2015/08/20 Javascript
利用jQuery设计一个简单的web音乐播放器的实例分享
2016/03/08 Javascript
javascript 小数乘法结果错误的处理方法
2016/07/28 Javascript
jQuery ajax 当async为false时解决同步操作失败的问题
2016/11/18 Javascript
node+experss实现爬取电影天堂爬虫
2016/11/20 Javascript
vue实现文章内容过长点击阅读全文功能的实例
2017/12/28 Javascript
JS Object.preventExtensions(),Object.seal()与Object.freeze()用法实例分析
2018/08/25 Javascript
小程序实现搜索框功能
2020/03/26 Javascript
Python的Twisted框架中使用Deferred对象来管理回调函数
2016/05/25 Python
python 简单的绘图工具turtle使用详解
2017/06/21 Python
python3使用pyqt5制作一个超简单浏览器的实例
2017/10/19 Python
python Pillow图像处理方法汇总
2019/10/16 Python
Python3 集合set入门基础
2020/02/10 Python
Python面向对象实现方法总结
2020/08/12 Python
CSS3新属性transition-property transform box-shadow实例学习
2013/06/06 HTML / CSS
英国著名的小众美容品牌网站:Alyaka
2017/08/08 全球购物
Harrods英国:世界领先的奢侈品百货商店
2020/09/23 全球购物
澳大利亚在线批发商:Simply Wholesale
2021/02/24 全球购物
旅游管理专业学生求职信
2013/09/28 职场文书
化学实验员岗位职责
2013/12/28 职场文书
学生生病请假条范文
2014/02/16 职场文书
2014年大班元旦活动方案
2014/02/26 职场文书
车辆工程专业求职信
2014/04/28 职场文书
合唱兴趣小组活动总结
2014/07/10 职场文书