您的位置:首页 > Web前端 > JavaScript

javascript 常见的闭包问题的解决办法

2017-04-07 15:51 459 查看
<html>
<head>
<title></title>
<script type="text/javascript">
<!--
function $(elem){
return document.getElementById(elem);
}
function tag(name,elem)
{
return (elem||document).getElementsByTagName(name);
}

function init()
{
var div=tag("div");
for(var i=0;i<div.length;i++)
{
div[i].onclick=function()
{
alert(i);
}
}
}
// -->
</script>
</head>
<body>
<div id="div" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">0</div>
<div id="div1" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">1</div>
<div id="div2" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">2</div>
<div id="div3" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">3</div>
<div id="div4" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">4</div>
<div id="div5" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">5</div>
<div id="div6" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">6</div>
<input type="button" value="click" onclick="init();">
</body>
</html>

上段代码本意是在每个div上都加一个事件,即每当点击div时,就显示此div的相应序号。但是运行程序时我们会发现,不论点击那个,只会显示7,这是什么愿因呢。--这就是闭包的问题 
原来 在js中,函数中在定义函数,就出现闭包了。此时外层函数中变量是可以在里层函数里利用的,即使外层函数结束。但是当外层中出现循环的时候,如果在里层函数中利用这个循环变量的话,会直接引用这个变量的最终值。 
就像上述代码演示的一样。 
如何解决呢。 
可以利用匿名函数来加以解决。匿名函数会制动执行,我们可以利用这一特性,来产生一个作用域,生命一个变量,来引用外层的循环变量。 
如代码所示: 

 

<html>
<head>
<title></title>
<script type="text/javascript"><!--
function $(elem){
return document.getElementById(elem);
}
function tag(name,elem)
{
return (elem||document).getElementsByTagName(name);
}

function init()
{
var div=tag("div");
for(var i=0;i<div.length;i++){
(function(){
var temp=i;
div[temp].onclick=function()
{
alert(temp);
}

})()

}
}
// --></script>
</head>
<body>
<div id="div" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">0</div>
<div id="div1" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">1</div>
<div id="div2" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">2</div>
<div id="div3" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">3</div>
<div id="div4" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">4</div>
<div id="div5" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">5</div>
<div id="div6" style=" border:1px solid #eee; background:#000;color:#fff;height:50px;width:300px">6</div>
<input type="button" value="click" onclick="init();">
</body>
</html>


由于在内层函数里只要出现循环变量的话 都是最终值,所以我们利用匿名函数 激发出一个作用域,在进入内层循环之前,有另一变量获得该循环变量的值,这一思想是处理闭包问题的精髓。 

如下例子:此时并没有明显的for循环,但是 根据上述思想,可以立即加以解决 问题 

 

<html>
<head>
<title> </title>
<script type="text/javascript"><!--

function $(elem){
return document.getElementById(elem);
}
var id=0;
function addDiv()
{
var text="testtestetsetstsetstst";
var div=$("div");
var divChild=document.createElement("div");
div.appendChild(divChild);
divChild.id="div"+id;
divChild.innerHTML=" <input type='text' id='row"+id+"'>"+text;
divChild.onclick=function()
{
alert("row"+id);
$("row"+id).value=text;
}
id++;
}
// --></script>
</head>
<body>
<div id="div" style="height:200px;width:300px">
</div>
<input type="button" value="click" onclick="addDiv();">
</body>
</html>


解决后代码:

<html>
<head>
<title> </title>
<script type="text/javascript"><!--

function $(elem){
return document.getElementById(elem);
}
var id=0;
function addDiv()
{
var text="testtestetsetstsetstst";
var div=$("div");
var divChild=document.createElement("div");
div.appendChild(divChild);
divChild.id="div"+id;
divChild.innerHTML=" <input type='text' style='color:#f00' id='row"+id+"'>"+text;
(function(){
var d=id;
divChild.onclick=function()
{

alert("row"+d);
$("row"+d).value=text;

}

})()
id++;
}
// --></script>
</head>
<body>
<div id="div" style="height:200px;width:300px">
</div>
<input type="button" value="click" onclick="addDiv();">
</body>
</html>


 

补充:看到有网友这样解决了问题: 

 

<html>
<head>
<title> </title>
<script type="text/javascript"><!--

function $(elem){
return document.getElementById(elem);
}
var id=0;
function addDiv()
{
var text="testtestetsetstsetstst";
var div=$("div");
var divChild=document.createElement("div");
div.appendChild(divChild);
divChild.id="div"+id;
divChild.innerHTML=" <input type='text' style='color:#f00' id='row'"+id+">"+text;

divChild.onclick=function(f){
return function(){
alert(f);
}
}(id)

id++;
}
// --></script>
</head>
<body>
<div id="div" style="background:#000;color:#fff;height:200px;width:300px">
</div>
<input type="button" value="click" onclick="addDiv();">
</body>
</html>

 

我个人的理解是 在进入内层循环之前 把id赋值给f,f在作为内层循环的参数,其思想应该是一样的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: