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 相关文章推荐
仅用[]()+!等符号就足以实现几乎任意Javascript代码
Mar 01 Javascript
jquery队列函数用法实例
Dec 16 Javascript
Bootstrap插件全集
Jul 18 Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
Aug 05 Javascript
js仿小米手机上下滑动效果
Feb 05 Javascript
使用JavaScript实现表格编辑器(实例讲解)
Aug 02 Javascript
vue Element-ui input 远程搜索与修改建议显示模版的示例代码
Oct 19 Javascript
解决vue build打包之后首页白屏的问题
Mar 06 Javascript
浅谈React的最大亮点之虚拟DOM
May 29 Javascript
electron 安装,调试,打包的具体使用
Nov 06 Javascript
vue-drag-chart 拖动/缩放图表组件的实例代码
Apr 10 Javascript
JS封装cavans多种滤镜组件
Feb 15 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过滤危险html代码的函数
2008/07/22 PHP
PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
2012/04/09 PHP
php实现下载限制速度示例分享
2014/02/13 PHP
php里array_work用法实例分析
2015/07/13 PHP
thinkPHP+ajax实现统计页面pv浏览量的方法
2017/03/15 PHP
PHP基于SPL实现的迭代器模式示例
2018/04/22 PHP
js过滤HTML标签以及空格的思路及代码
2013/05/24 Javascript
jquery cookie的用法总结
2013/11/18 Javascript
js操作模态窗口及父子窗口间相互传值示例
2014/06/09 Javascript
javascript实现客户端兼容各浏览器创建csv并下载的方法
2015/03/23 Javascript
js实现时间显示几天前、几小时前或者几分钟前的方法集锦
2015/05/29 Javascript
基于JavaScript Array数组方法(新手必看篇)
2016/08/20 Javascript
Vuejs第七篇之Vuejs过渡动画案例全面解析
2016/09/05 Javascript
原生Aajax 和jQuery Ajax 写法个人总结
2017/03/24 jQuery
JavaScript原型继承_动力节点Java学院整理
2017/06/30 Javascript
Vue.js实现实例搜索应用功能详细代码
2017/08/24 Javascript
p5.js实现斐波那契螺旋的示例代码
2018/03/22 Javascript
微信小程序实现图片翻转效果的实例代码
2019/09/20 Javascript
js实现div色块拖动录制
2020/01/16 Javascript
vue3.0 项目搭建和使用流程
2021/03/04 Vue.js
Python中关键字is与==的区别简述
2014/07/31 Python
Python动态加载模块的3种方法
2014/11/22 Python
python使用xlrd模块读写Excel文件的方法
2015/05/06 Python
Python编程产生非均匀随机数的几种方法代码分享
2017/12/13 Python
Python中顺序表的实现简单代码分享
2018/01/09 Python
python实现pdf转换成word/txt纯文本文件
2018/06/07 Python
python scipy卷积运算的实现方法
2019/09/16 Python
CSS3 3D位移translate效果实例介绍
2016/05/03 HTML / CSS
购买英国原创艺术:Art Gallery
2018/08/25 全球购物
别名指示符是什么
2012/10/08 面试题
进口业务员岗位职责
2014/04/06 职场文书
会计学专业自荐信
2014/06/25 职场文书
2014领导干部学习焦裕禄同志先进事迹思想汇报
2014/09/19 职场文书
庆祝儿童节标语
2014/10/09 职场文书
幼儿园教师个人总结
2015/02/05 职场文书
2016重阳节红领巾广播稿
2015/12/18 职场文书