利用閉包解決for循環里onclick事件不能捕捉實時i值問題


問題描述

我們都知道,如果我們對於一組元素(相同的標簽)同時進行onclick事件處理的時候(在需要獲取到索引的時候),一般是寫一個for循環,但是onclick是一個異步調用的,所以會帶來一個問題,當我們觸發這個事件的時候,我們能獲取的i值是for完整執行完后i的值,而不能獲取到代碼順序里i的值

 

首先看一段代碼:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
    <button>0</button>
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>
    <script> 
        var btn=document.getElementsByTagName('button');
        for(var i=0;i<btn.length;i++){ 
            btn[i].onclick=function(){ 
                console.log(i);
            }
        }
    </script>
</body>
</html>

然后運行一下,當時作為一名天真的js初學者理所當然的認為分別點擊不同的額按鈕,會分別的打印出0、1、2、3、4,然而事與願為,現實和理想總是存在差距,點擊不同的按鈕,打印卻都是5,百思不得其解,不科學啊! 
最后百度了一番才恍然大悟,原來console.log(i)里的i在循環完成的時候被賦值成了5,而每個按鈕的onclick都被賦值了同一個function,也就是說每個function里的i指的是同一個i,i=5,自然每個點擊都會打印出5,那么該怎么解決呢?! 

利用閉包解決

再看接下來這段代碼:

 <script> 
        var btn=document.getElementsByTagName('button');
        for(var i=0;i<btn.length;i++){ 
            (function(n){ //這個是function里n,即function的形參,也可以換成j,換成什么變量名都無所謂
                btn[n].onclick=function(){ 
                    console.log(i+'-'+n); //i總是等於5,而n則是點擊的數
                }
            })(i);//這是循環中的i,被作為參數傳入
        }
    </script>

 

 

再運行這段代碼,就可以得到你想要的效果,但是是為什么呢? 
知道了原因就好辦了,利用閉包把每個function里的i都變成不同的i就行了,當時作為一名初學者還不懂閉包,也是后來才理解的。 
循環中的function自調用,將循環中的i作為參數傳入function中,此時,function中的i已經不是循環中的i了(這里有點繞,其實形參i,即function里的i換成什么變量名都行),而是在內存中開辟了一個內存空間存儲了作為參數傳進來的i的值,這樣function中的就不會隨着循環中的i的值的改變而改變了,就可以打印出你要的結果了。

 

原理:

閉包的局部作用域。由於這個你們函數總是和代碼執行順序一樣的,所以n可以實時記錄i的值。由於for每執行一次,就執行一次匿名函數,每一次執行有自己的執行環境,有着自己的作用域鏈,所以用這函數里面一個變量來記錄一下實時的i的值,這個n是不會隨着i的改變而改變的

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM