关于js批量绑定事件的问题

<body>  
<ul id="list">  
<li>1</li>  
<li>2</li>  
<li>3</li>  
<li>4</li>  
<li>5</li>  
</ul>  
<script>  
var list_obj = document.getElementsByTagName('li');  
for (var i = 0; i <= list_obj.length; i++) {        
  list_obj[i].onclick = function() {      
    alert(i);      
  }  
}  
</script>  
</body>  

for循环绑定完事件最后执行的时候都是最后一个事件相同,点击的时候弹出的不是0 1 2 3 4,而是5,这是为什么呢 如何解决

阅读 6.1k
7 个回答

当调用onclick事件的时候,会向上找到i对象的值。这个时候,由于已经循环完毕,所以i的值是5

解决方法:

闭包

for (var i = 0; i <= list_obj.length; i++) {
  list_obj[i].onclick = (function(i){
    return function() {  alert(i); }
  })(i);  
} 

ES6

for (let i = 0; i <= list_obj.length; i++) {        
  list_obj[i].onclick = function() {      
    alert(i);      
  }  
}  

js闭包问题,当上述代码执行完时,i的值为5,因为鼠标点击事件是异步的,发生在代码执行之后,此时执行回调函数时,函数并没有保存i这个变量的值,它会通过闭包即作用域链向上获取i值,所以得到的都是5
如果想弹出0,1,2,3,4,可将使用匿名函数创建作用域,代码如下:

 list_obj[i].onclick = (function(x) {      
    alert(x);      
 })(i)  

用闭包把绑定时的i值hold住就能解决这个问题了...这是JS中常出错的典型问题...

楼主好好看一下 JavaScript 中的闭包

因为是触发onclick事件的时候才回去执行function,而此时的function等同于

function(){
    //此时的i为5,所以
    alert("5")
}

for (var i = 0; i <= list_obj.length; i++)

TO

for (let i = 0; i <= list_obj.length; i++)

给你举个例子,最好自己复制下试试。

<html>
<head></head>
<body>

<div name="dvTest" style="width: 100px; height: 50px; background-color: #ff0000"></div> 
<div name="dvTest" style="width: 100px; height: 50px; background-color: #00ff00"></div> 
<div name="dvTest" style="width: 100px; height: 50px; background-color: #0000ff"></div> 
<p></p>
<div name="dvTest2" style="width: 100px; height: 50px; background-color: #ff0000"></div> 
<div name="dvTest2" style="width: 100px; height: 50px; background-color: #00ff00"></div> 
<div name="dvTest2" style="width: 100px; height: 50px; background-color: #0000ff"></div> 

<script>
    var dvTest = document.getElementsByName('dvTest');
    var dvTest2 = document.getElementsByName('dvTest2');

    for(let i=0; i<dvTest.length; i++)
    {
        dvTest[i].onmouseover=function()
        {
             console.log(i);
         }
    }


    for(var k=0; k<dvTest2.length; k++)
    {
        dvTest2[k].onmouseover=function()
        {
             console.log(k);
         }
    }



</script>
</body>
</html>

你比较一下let和var来定义for中变量的不同。鼠标滑过前三个色块,看浏览器调试窗口的输出。再滑过后三个色块看看输出什么。

clipboard.png

推荐问题