函數閉包問題的學習

在前端面試中時常會被問到閉包這個概念,那麼閉包到底是什麼呢?怎麼去解讀這個概念呢?
其實在別的編程語言裏面有代碼塊級作用域這麼一個概念,但是在JS中,不在一個代碼塊內的變量是可以被訪問跟修改的,爲了保護這些私有變量不受外界的改變,所以就有了閉包這個概念。
<ul id="myUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>
<script>
    var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        myLi[i].onclick=function(){
            alert(i+1);
        }
    }

這裏的alert就會直接彈出4,因爲for循環裏面的那個匿名函數,是個異步事件,也就是說代碼,順序執行時,不會執行這個函數,只有當觸發事件產生,纔會執行這個函數,而此時的循環早已結束,此時的i已經爲3,所以彈出4。此時應用閉包就可以解決問題,其實嚴格的說,只要是定義了一個函數,這個函數執行時就產生了閉包,閉包只是一種運行機制。

var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        ;(function(i){
            myLi[i].onclick=function(){
                alert(i+1);
            }
        })(i)
    }
 var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        myLi[i].onclick=(function(i){
            return function(){
                alert(i+1);
            }
        })(i)
    }

修改成上述兩種方式都可以,函數在執行的時候,就會形成一個私有作用域,而這個作用域裏面定義的參數,是不受外界干擾的。解決異步,即保護作用域裏面的參數不受外界的干擾。
關於定時器以setTimeout爲例

window.setTimeout(fn(),1000);

此時,會直接執行fn(),並將fn的返回值,加入到setTimeout的隊列中,
而且setTimeout天生就是一個異步的。可看一下代碼,可見 閉包是處理異步的非常好用的方法。

for(var i=0;i<myLi.length;i++){
       window.setTimeout((function(i){
           return function(){myLi[i].style.left=100*(i+1)+"px";
           }
       })(i),(i+1)*1000)
    }

關於函數作用域的釋放問題,一般情況下當一個函數執行完之後,這個函數所創建的作用域,將會消失,當這個函數再次執行時,會再 創建一個作用域,前後兩個作用域不干擾。若這個函數中產生了閉包,且這個閉包被一個時間綁定,或者返回給了一個變量,那麼這個函數創建的作用域將不會消失。

function fn(){
    var i=0;
    return function(){
        console.log(i++);
    }
}
var a=fn();
a();
a();

兩次打印分別爲0和1。是因爲 返回的函數賦給了變量,在var a=fn()這一句中函數所創建的作用域就不會被釋放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章