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 fullscreen全屏实现代码
Apr 09 Javascript
DOM 基本方法
Jul 18 Javascript
jquery 问答知识整理
Feb 11 Javascript
让你的CSS像Jquery一样做筛选的实现方法
Jul 10 Javascript
解决自定义$(id)的方法与jquery选择器$冲突的问题
Jun 14 Javascript
jQuery实现HTML5 placeholder效果实例
Dec 09 Javascript
js实现模拟计算器退格键删除文字效果的方法
May 07 Javascript
浅谈jquery的map()和each()方法
Jun 12 Javascript
基于Vue2.X的路由和钩子函数详解
Feb 09 Javascript
深入浅出理解JavaScript闭包的功能与用法
Aug 01 Javascript
Vue源码分析之Vue实例初始化详解
Aug 25 Javascript
微信小程序加载机制及运行机制图解
Nov 27 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字符串处理的10个简单方法
2010/06/30 PHP
Yii框架登录流程分析
2014/12/03 PHP
golang 调用 php7详解及实例
2017/01/04 PHP
php使用curl实现简单模拟提交表单功能
2017/05/15 PHP
PHP数据库操作四:mongodb用法分析
2017/08/16 PHP
js获取提交的字符串的字节数
2009/02/09 Javascript
javascript错误的认识不用关心内存管理
2012/12/15 Javascript
JS 实现Table相同行的单元格自动合并示例代码
2013/08/27 Javascript
JS 实现点击a标签的时候让其背景更换
2013/10/15 Javascript
JavaScript插件化开发教程 (二)
2015/01/27 Javascript
jquery简单实现网页层的展开与收缩效果
2015/08/07 Javascript
javascript比较语义化版本号的实现代码
2016/09/09 Javascript
js转换对象为xml
2017/02/17 Javascript
详解Vue整合axios的实例代码
2017/06/21 Javascript
ReactNative实现图片上传功能的示例代码
2017/07/11 Javascript
详解Vue2中组件间通信的解决全方案
2017/07/28 Javascript
ES6中Array.find()和findIndex()函数的用法详解
2017/09/16 Javascript
Vue2仿淘宝实现省市区三级联动
2020/04/15 Javascript
利用原生JavaScript实现造日历轮子实例代码
2019/05/08 Javascript
微信小程序Page中data数据操作和函数调用方法
2019/05/08 Javascript
微信小程序如何使用云开发
2019/05/17 Javascript
JS实现商品橱窗特效
2020/01/09 Javascript
JS代码检查工具ESLint介绍与使用方法
2020/02/04 Javascript
浅析python 中__name__ = '__main__' 的作用
2014/07/05 Python
python正则表达式中的括号匹配问题
2014/12/14 Python
Python类定义和类继承详解
2015/05/08 Python
Python序列化基础知识(json/pickle)
2017/10/19 Python
使用APScheduler3.0.1 实现定时任务的方法
2019/07/22 Python
Python+opencv+pyaudio实现带声音屏幕录制
2019/12/23 Python
皇马官方商城:Real Madrid Store
2016/09/02 全球购物
巴西备受欢迎的服装和生活方式品牌:FARM Rio
2020/02/04 全球购物
企业标语大全
2014/07/01 职场文书
2019年作为一名实习生的述职报告
2019/09/29 职场文书
golang 如何通过反射创建新对象
2021/04/28 Golang
Jupyter Notebook内使用argparse报错的解决方案
2021/06/03 Python
《总之就是很可爱》新作短篇动画《总之就是很可爱~制服~》将于2022年夏天播出
2022/04/07 日漫