1. 程式人生 > >js閉包

js閉包

一次 什麽 常用 技術 erro urn script 寫法 func

項目中用到了在for循環內部對按鈕綁定事件,但運行時事件觸發始終顯示的是最後一次綁定的結果,思來想去,跟js閉包有關,加以記錄。

js中分:全局變量 和 局部變量

  全局變量:可以在任意位置訪問的量就叫全局變量

    

1 var age = 20;
2 function a(){
3     console.log(age); >>20
4 }
5 a();

  局部變量:函數中用var定義的變量,只能在函數中訪問這個變量,函數外部訪問不了。

1 function a(){
2     var age = 20;
3 }
4 a();
5 console.log(age); >> Uncaught ReferenceError: age is not defined

註意點1:在函數中如果不使用var定義變量那麽js引擎會自動添加成全局變量。

註意點2:全局變量從創建的那一刻起就會一直保存在內存中,除非你關閉這個頁面,局部變量當函數運行完以後就會銷毀這個變量,假如有多次調用這個函數它下一次調用的時候又會重新創建那個變量,既運行完就銷毀,回到最初的狀態,簡單來說局部變量是一次性的,用完就扔,下次要我再重新創建。

函數的相關知識點:

1. 一個函數內可以嵌套多個函數

   2. 函數裏面的子函數可以訪問它上級定義的變量,註意不只是一級,如果上級沒有會繼續往上級找,直到找到為止,如果找到全局變量到找不到就會報錯。

    

技術分享
1 function a(){
2     var name = "追夢子";
3     function b(){
4         console.log(name); >> "追夢子"
5     }
6     b();
7 }
8 a();
技術分享

   3. 函數的另外一種調用形式,你可以把它叫做自調用,自己調用自己,達到自執行的效果。

   

1 var a = 0;
2 (function(){
3    console.log(++a); >>1
4 })()

這種方式用()把內容包裹起來,後面的()表示執行這個函數,可能你會問為什麽要把函數包起來,如果不包裹起來,js會把它當作函數聲明來處理,如果包裹起來就是表達式,還沒有看懂就上網查吧。

開始我們正式閉包部分---------------------------- 幣包 ---------------像錢包一樣的東西,可以把東西包裹起來----------

首先我們來看看為什麽需要學習閉包,加以理解 -- 0 v 0- -

1 function a(){
2    var num = 0;
3    console.log(++num);
4 }
5 a(); >>1
6 a(); >>1

上面代碼輸出了兩次1,為什麽呢?如果你有看我上面的關於變量部分肯定能夠想到個大概。

  前面我們說過了函數執行完以後,裏面的變量(即局部變量)就會銷毀,下一次運行又會重新創建那個變量,所以雖然你第一次++num了但是這個變量在第一次執行完畢以後就被銷毀了。

那麽我們怎麽樣才能確保第一次的變量不被銷毀,那麽就需要我們的閉包出場了。

溫馨提示:JavaScript中有回收機制,函數沒有被引用執行完以後這個函數的作用域就會被銷毀,如果一個函數被其他變量引用,這個函數的作用域將不會被銷毀,(簡單來說就是函數裏面的變量會被保存下來,你可以理解成全局變量。)

…………………………………………………………………………………… 當 當 當 ................. 下面有請我們的幣包同誌

技術分享
function a(){
    var aa = 0;
    function b(){
        aa ++;
        console.log(aa);
    }
    return b;
}
var ab = a();
ab(); //1
ab(); //2
技術分享

看到了吧裏面的變量的值沒有被銷毀,因為函數a被外部的變量ab引用,所以變量aa沒有被回收。

如果某個函數被它的父函數之外的一個變量引用,就形成了一個閉包

還有一種更為常用的閉包寫法

技術分享
var bi = (function(){
    var a = 0;
    function b(){
        a ++;
        console.log(a);
    }
    return b;
})();

bi(); //1
bi(); //2
bi(); //3
技術分享

執行過程分析:

  首先把一個自執行函數賦值給了bi,這個自執行函數運行完成以後就bi的值就變成了

function b(){
    a ++;
    console.log(a);
}

  因為我們在上面的代碼return回去了b,然後因為這個自執行函數被bi引用所以裏面的變量a並沒有因為這個自執行函數執完而銷毀,而是保存到了內存中,所以我們多次打印bi()就成了1、2、3

下面我來說一個閉包的使用場景吧。

  沒有使用閉包的版本

技術分享
window.onload = function(){
    var ul = document.getElementsByTagName("ul")[0];
    var li = ul.getElementsByTagName("li");
    for(var i=0;i<li.length;i++){
        li[i].onclick = function(){
            console.log(i); //不管我怎麽點都是返回6
        }
    }
}
技術分享

  使用了閉包的版本

技術分享
window.onload = function(){
    var ul = document.getElementsByTagName("ul")[0];
    var li = ul.getElementsByTagName("li");
    for(var i=0;i<li.length;i++){
        (function(i){
            li[i].onclick = function(){
                console.log(i); //點擊第幾個返回第幾個
            }
        })(i)
    }
}

js閉包