javascript 避免闭包引发的问题

 更新时间:2009年03月17日 23:37:22   作者:  
闭包的功能强大,但如果没有正确理解闭包的概念,其结果往往出乎人的意料。例如,下面是一个较常见的问题
<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 parseInt 大改造

    javascript parseInt 大改造

    还隐约记得第一次遇到 parseInt这个诡异问题的时候,以为发现了IE的BUG,兴奋不已。
    2009-09-09
  • JavaScript之BOM构成和常用事件详解

    JavaScript之BOM构成和常用事件详解

    这篇文章主要为大家介绍了JavaScript BOM构成和常用事件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • JavaScript实现音乐自动切换和轮播

    JavaScript实现音乐自动切换和轮播

    这篇文章主要为大家详细介绍了JavaScript实现音乐自动切换和轮播效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • 纯JS代码实现气泡效果

    纯JS代码实现气泡效果

    js气泡效果,在项目需求中经常遇到。今天小编把大概实现步骤分享到脚本之家平台,感兴趣的朋友可以参考下
    2016-05-05
  • javascript trie前缀树的示例

    javascript trie前缀树的示例

    这篇文章主要介绍了javascript trie单词查找树的示例,详细的介绍了trie的概念和实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • 深入理解JavaScript中的for循环

    深入理解JavaScript中的for循环

    这篇文章主要给大家深入的介绍了JavaScript中的for循环,其中包括ES5中的三种for循环,分别是简单for循环、for-in以及forEach,另外还详细介绍了ES6新增的一种循环:for-of ,有需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-02-02
  • ES6新增的math,Number方法

    ES6新增的math,Number方法

    ES6新增的math,Number方法,小编觉得非常不错,需要的朋友参考下吧
    2017-08-08
  • js实现在网页上简单显示时间的方法

    js实现在网页上简单显示时间的方法

    这篇文章主要介绍了js实现在网页上简单显示时间的方法,实例分析了javascript实时显示时间的技巧,需要的朋友可以参考下
    2015-03-03
  • JS Angular 服务器端渲染应用设置渲染超时时间​​​​​​​

    JS Angular 服务器端渲染应用设置渲染超时时间​​​​​​​

    这篇文章主要介绍了JS Angular服务器端渲染应用设置渲染超时时间,​​​​​​​通过setTimeout模拟一个需要5秒钟才能完成调用的API展开详情,需要的小伙伴可以参考一下
    2022-06-06
  • js中把JSON字符串转换成JSON对象最好的方法

    js中把JSON字符串转换成JSON对象最好的方法

    这篇文章主要介绍了js中把JSON字符串转换为JSON对象最好的方法,需要的朋友可以参考下
    2014-03-03

最新评论