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 选择器、过滤器介绍
Feb 14 Javascript
jQuery写的日历(包括日历的样式及功能)
Apr 23 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
Jan 06 Javascript
js判断url是否有效的两种方法
Mar 04 Javascript
javascript基本包装类型介绍
Apr 10 Javascript
详细解读AngularJS中的表单验证编程
Jun 19 Javascript
用JavaScript实现PHP的urlencode与urldecode函数
Aug 13 Javascript
js中字符串编码函数escape()、encodeURI()、encodeURIComponent()区别详解
Apr 01 Javascript
Bootstrap Validator 表单验证
Jul 25 Javascript
axios向后台传递数组作为参数的方法
Aug 11 Javascript
JavaScript数据结构与算法之二叉树插入节点、生成二叉树示例
Feb 21 Javascript
linux服务器快速卸载安装node环境(简单上手)
Feb 22 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+jQuery+Ajax实现用户登录与退出
2015/04/27 PHP
yii2分页之实现跳转到具体某页的实例代码
2016/06/02 PHP
PHP 与 UTF-8 的最佳实践详细介绍
2017/01/04 PHP
js禁止小键盘输入数字功能代码
2011/08/01 Javascript
从js向Action传中文参数出现乱码问题的解决方法
2013/12/29 Javascript
js完美实现@提到好友特效(兼容各大浏览器)
2015/03/16 Javascript
易操作的jQuery表单提示插件
2015/12/01 Javascript
js实现瀑布流的三种方式比较
2020/06/28 Javascript
简单了解JavaScript操作XPath的一些基本方法
2016/06/03 Javascript
Highcharts学习之坐标轴
2016/08/02 Javascript
JS简单获取当前年月日星期的方法示例
2017/02/07 Javascript
nodejs操作mongodb的填删改查模块的制作及引入实例
2018/01/02 NodeJs
webpack4与babel配合使es6代码可运行于低版本浏览器的方法
2018/10/12 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
ant-design-vue 实现表格内部字段验证功能
2019/12/16 Javascript
Python制作钉钉加密/解密工具
2016/12/07 Python
Python UnboundLocalError和NameError错误根源案例解析
2018/10/31 Python
python http基本验证方法
2018/12/26 Python
django实现更改数据库某个字段以及字段段内数据
2020/03/31 Python
详解css3 Transition属性(平滑过渡菜单栏案例)
2017/09/05 HTML / CSS
英国图书音像网站:Hive.co.uk(图书、电子书、DVD、蓝光、音乐CD等)
2017/10/16 全球购物
重新定义牛仔布,100美元以下:Warp + Weft
2018/07/25 全球购物
AJax面试题
2014/11/25 面试题
教师节商场活动方案
2014/02/13 职场文书
高中军训感想300字
2014/03/04 职场文书
搞笑的爱情检讨书
2014/10/01 职场文书
买房子个人收入证明
2014/10/12 职场文书
12.4全国法制宣传日活动总结
2014/11/01 职场文书
教学督导岗位职责
2015/04/10 职场文书
2015年环境监察工作总结
2015/07/23 职场文书
食品卫生管理制度
2015/08/06 职场文书
教你怎么用Python处理excel实现自动化办公
2021/04/30 Python
Python爬取某拍短视频
2021/06/11 Python
java高级用法JNA强大的Memory和Pointer
2022/04/19 Java/Android
PHP 时间处理类Carbon
2022/05/20 PHP
SQLyog的下载、安装、破解、配置教程(MySQL可视化工具安装)
2022/09/23 MySQL