关于在for循环中绑定事件打印变量i是最后一次

在for循环中绑定事件打印变量i是最后一次,其原因是函数引用的外部变量都是最后一次的值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        #box{
            width:100px;
            height:100px;
            background-color:pink;
        }
    </style>
    <script src="index.js"></script>
</head>
<body>
    <div id="box"></div>
    <script>
	    var box = document.getElementById("box");
	    var num = 0;
	    function a(){
	        console.log(num);
	    }
	
	    box.onclick = function(){
	        num ++;
	        a(); // 1,2,3,4....每次单击都会加1,说明函数引用外部变量是引用那个变量的最后一次的值。
	    }
    </script>
</body>
</html>

再来看一个例子:

window.onload = function(){
    var box = document.getElementById("box");
    var num = 0;
    for(var i=0;i<10;i++){
        box.onclick = function(){
            console.log(i); //总是打印10
        }
    }    
}

在这个函数里面的i其实引用的是最后一次i的值,为什么不是1,2,3,4…呢?因为在你for循环的时候,你并没有执行这个函数,这个函数是在点击的时候才执行的,当执行这个函数的时候,它发现它自己没有这个变量i,于是向它的作用域链中查找这个变量i,因为当单击这个box的时候已经for循环完了,所以储存在作用域链里面的i的值就是10,最后就打印出来10了。

for(var i=0;i<10;i++){
    function a(){
        console.log(i);
    }
    a(); //1,2,3,4,5....
}

为什么这样就可以呢?因为你在循环变量i的时候已经执行了函数a,自然变量i是什么就打印出来什么。

现在知道为什么绑定事件的时候打印出来的是最后一次的for循环的值了吧。

如果你知道理解这段话,我相信你知道怎么去解决这个问题。

解决方法1:让这个函数直接执行。

解决方法2:将每次for循环中的变量i保存到某个地方。

方法1:

window.onload = function(){
    var box = document.getElementById("box");
    var num = 0;
    for(var i=0;i<10;i++){
        box.onclick = a();
        function a(){
            console.log(i); //1,2,3,4.....
        }
    }
    
}

虽然这样可以打印出每次的变量i的值,但是我们没有点击box的时候它已经执行完了,直接无视了点击事件,也就是说这个点击事件已经可有可无了,所以我们用这种方法在绑定事件中就显得不那么可用了,那我们用方法2试试吧。

方法2:

window.onload = function(){
    var div = document.getElementsByTagName("div");
    var num = 0;
    for(var i=0;i<div.length;i++){
        (function(i){
            div[i].onclick = function(){
                console.log(i); 
            }
        })(i)
    }
    
}

利用闭包,成功打印每个i的值,原理就是通过自执行函数,并且将变量i保存到这个自执行函数的参数中。

posted @ 2022-07-20 18:16  猫老板的豆  阅读(88)  评论(0编辑  收藏  举报