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 相关文章推荐
让人期待的2011年度最佳 jQuery 插件分享
Mar 16 Javascript
用jquery实现点击栏目背景色改变
Dec 10 Javascript
深入理解javascript变量声明
Nov 20 Javascript
Angular ng-repeat指令实例以及扩展部分
Dec 26 Javascript
jQuery日期范围选择器附源码下载
May 23 jQuery
jQuery AJAX 方法success()后台传来的4种数据详解
Aug 08 jQuery
React 源码中的依赖注入方法
Nov 07 Javascript
五分钟搞懂Vuex实用知识(小结)
Aug 12 Javascript
vue父子组件通信的高级用法示例
Aug 29 Javascript
React中使用UMEditor的方法示例
Dec 27 Javascript
Vue中el-form标签中的自定义el-select下拉框标签功能
Apr 20 Javascript
原生JS实现拖拽功能
Dec 16 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 操作excel文件的方法小结
2009/12/31 PHP
PHP中将字符串转化为整数(int) intval() printf() 性能测试
2020/03/20 PHP
为PHP5.4开启Zend OPCode缓存
2014/12/26 PHP
php实现多维数组排序的方法示例
2017/03/23 PHP
tp5框架无刷新分页实现方法分析
2019/09/26 PHP
jQuery学习3:操作元素属性和特性
2010/02/07 Javascript
JavaScript图片放大技术(放大镜)实现代码分享
2013/11/14 Javascript
jQuery 中国省市两级联动选择附图
2014/05/14 Javascript
jQuery Mobile页面返回不需要重新get
2016/04/26 Javascript
js和jq使用submit方法无法提交表单的快速解决方法
2016/05/17 Javascript
BootStrap智能表单实战系列(七)验证的支持
2016/06/13 Javascript
jQuery获取同级元素的简单代码
2016/07/09 Javascript
Node.js开发教程之基于OnceIO框架实现文件上传和验证功能
2016/11/30 Javascript
jQuery实现CheckBox全选、全不选功能
2017/01/11 Javascript
浅谈redux以及react-redux简单实现
2018/08/28 Javascript
JavaScript创建对象的四种常用模式实例分析
2019/01/11 Javascript
JavaScript中将值转换为字符串的五种方法总结
2019/06/06 Javascript
extjs4图表绘制之折线图实现方法分析
2020/03/06 Javascript
微信小程序实现搜索框功能及踩过的坑
2020/06/19 Javascript
Vue-router编程式导航的两种实现代码
2021/03/04 Vue.js
[14:24]Optic Gaming vs PSG LGD BO3
2018/06/07 DOTA
Python升级提示Tkinter模块找不到的解决方法
2014/08/22 Python
Python的Bottle框架的一些使用技巧介绍
2015/04/08 Python
matplotlib绘制动画代码示例
2018/01/02 Python
python 信息同时输出到控制台与文件的实例讲解
2018/05/11 Python
使用Python和Scribus创建一个RGB立方体的方法
2019/07/17 Python
python 求定积分和不定积分示例
2019/11/20 Python
Python3 main函数使用sys.argv传入多个参数的实现
2019/12/25 Python
地球鞋加拿大官网:Earth Shoes Canada
2020/11/17 全球购物
毕业生的自我鉴定该怎么写
2013/12/02 职场文书
二年级体育教学反思
2014/01/15 职场文书
职业培训师职业生涯规划
2014/02/18 职场文书
民间借贷协议书范本
2014/10/01 职场文书
2014年安置帮教工作总结
2014/12/11 职场文书
关于环保的宣传稿
2015/07/23 职场文书
2016党员发展对象培训心得体会
2016/01/08 职场文书