JS中的閉包

閉包是JS中的一個重要的概念,在模塊封裝,保存變量中有着重要的作用,掌握閉包在前端開發中佔着非常重要的角色。在瞭解閉包之前我們需要了解一下JS的垃圾回收機制和作用域。

一、垃圾回收機制

我們知道前端開發中,JS中最好不要存在過多的全局變量,這樣可以避免全局變量的污染,和在創建新的變量或者函數中存在衝突的情況。所以有時候我們可能會看到如下所示:

var a = 1;
var b = a;
var a = null;

即將全局中不再使用的變量賦值爲null。那大家知道爲什麼賦值給null,爲什麼不賦值給undefined?

這個就牽涉到JS的垃圾回收機制了,JS中的垃圾回收機制將會每隔一段時間,按照一定的算法和規則,找出不再使用的變量對象,進行回收,提高頁面的性能,而a = null正是讓a失去賦值1的引用,此時a就變成不再使用的變量對象了,將會在下一次的垃圾回收中被銷燬。

二、作用域

JS中存在兩種作用域,全局作用域和函數作用域(第三種作用域eval因爲我們平常很少用到,並且浪費計算機算力,所以我們很少使用,這裏不做討論)。

var a = 1;
function demo(){
    var b = 2;
    console.log(a);
}
demo(); //1
console.log(b);  //  b is not defined

上面函數存在兩個作用域,一個是全局作用域window,一個是函數demo的作用域,按照規範是函數作用域可以訪問全局變量,而全局變量是不能訪問函數作用域的變量,所以在執行demo函數的時候,能夠打印出1,而在打印b的時候會報錯沒有找到。

三、閉包
var a = 1;
function demo(){
    var b = 2;
    function c(){
        console.log(b);
    }
    a = c;
}
demo();
a();  //2

上面代碼執行流程爲先執行demo函數,在內存中創建函數function(){console.log(b)},變量c指向該函數,通過a=c,a也指向該函數,當demo函數執行完畢後,不再存在c變量,然後執行a(),由於a已經獲得函數c的引用,所以執行結果過打印出2。

閉包經典例子:
點擊li標籤,打印當前標籤的索引。

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var ul = document.getElementsByTagName("ul")[0];
    var i = 0;
    var lis = ul.getElementsByTagName("li");
    var len = lis.length;
    for(;i<len;i++){
        (function(j){
            lis[i].onclick = function (){
                console.log(j);
            }
        })(i)   
    }
</script>

爲什麼需要使用立即執行函數(function(){})()?

在執行for循環的過程中,點擊事件並沒有觸發,相應的函數也不會執行。如果不使用閉包保存i的話,當我們在點擊li標籤的時候,此時for循環已經全部執行完畢,此時i=2,無論點擊任何i標籤將會打印同樣的結果。

使用立即執行函數的目的就是將每次for循環的i值保存在當前函數中,這樣我們在每一次的點擊li標籤的時候就能獲取當前li的索引值了。

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