JavaScript中閉包的理解

從個人認知層次出發,依次寫下理解

1.接觸過js的朋友大都知道下面的錯誤:

<style>
        span {
            background-color: #ffa500;
            cursor: pointer;
            color: #fff;
        }
    </style>
    <div id="demo">
        <span>0</span> <span>1</span> <span>2</span> <span>3</span>
    </div>
我想通過點擊span得到它的序列號:
var demo = document.getElementById("demo");
    var spans = demo.children;
    for(var i=0;i<spans.length;i++){
        spans[i].onclick = function() {
            alert(i);
        }
    }
此時不管點擊那個span彈出的結果都爲4

那麼我做如下修改:
for(var i=0;i<spans.length;i++){
        spans[i].onclick = function(num) {
            return function() {
                alert(num)
            }
        }(i);
    }

這樣就能得到我們想要的結果了。這段代碼 相當於:
for(var i=0;i<spans.length;i++){
        spans[i].onclick = fun(i);
        function fun(num) {
            return function() {
                alert(num)
            }
        }
    }

當然這樣也是可以的:
for(var i=0;i<spans.length;i++){
        spans[i].index = i;
        spans[i].onclick = function () {
            alert(this.index);
        }
    }
2.變量作用域
下面代碼
<script>
    var key = "你好嗎";
    function fun() {
        var num = 10; 
        console.log(num);
        console.log(key);
    }
    fun();
    console.log(num);
</script>
控制檯會輸出:10      你好嗎  num is not defined    這段代碼中  key 爲全局變量,在函數體內處處可見。執行函數fun(),他能識別key這個全局變量已及其內部變量num;控制檯輸出 10  你好嗎  而 num屬於fun()函數的內部變量,他無法在fun()函數以外被識別。控制檯輸出 num is  not  defined。

3.弄清了變量的作用域後,讓我們試圖理解下閉包的含義
在程序語言中,所謂閉包,是指語法域位於某個特定的區域,具有持續參照(讀寫)位於該區域內自身範圍之外的執行域上的非持久型變量值能力的段落。這些外部執行域的非持久型變量神奇地保留他們在閉包最初定義(或創建)時的值。
我想很多同學可能跟我一樣看了之後一臉懵逼,別急看看這個: 我們可以用一個函數,去訪問另外一個函數的內部變量的方式就是閉包。也就是說:當內部函數在定義他的作用域的外部被引用時,就創建了該內部函數的一個閉包。額,還是疑惑?其實閉包就是能夠讀取其他函數內部變量的函數。   閉包歸根結底就是一個函數。 

在彈出結果爲4 的那段代碼中。每個span的onclick事件爲內部函數,他引用了for()內的變量i。我們稱onclick函數就是閉包。該程序運行時,for循環開始執行,直到i爲4時,for循環終止。由於js並不存在塊級作用域,而i又是全局作用域下的變量,onclick事件並不能保存i的值。每當span被點擊時,就會記錄i這個變量。此時彈出i的值 4。

4.可能有些同學對修改後的第一段代碼還是一頭霧水,其實這裏使用了一個立即執行的函數.後面的括號(i)表示把i當參數傳入,函數立即執行,num(形參)用來保存得到的i的值

5.實例

如下代碼一:
<script>
    function outerFun(){
        function innerFun(){
             var a=0;		
            a++;
            alert(a);
        }
        return innerFun; 
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>
a爲函數 innerFun()的內部變量,在被調用時每次都被重新賦值爲0   該函數運行結果爲 1  1  1  1 

代碼二:
<script>
    var a = 0;
    function outerFun(){
        function innerFun(){
            a++;
            alert(a);
        }
        return innerFun;
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>


a爲全局變量,

輸出結果爲 :  1      2                     3               4

代碼三:
<script>
    function outerFun()
    {
        var a=0;
        function innerFun()
        {
            a++;
            alert(a);
        }
        return innerFun;
    }
    var obj=outerFun();
    obj();  obj();
    var obj2=outerFun();
    obj2();  obj2();
</script>


在函數被重新定義爲obj2時,變量a重新回到了他最初被定義時的值 0;


輸出結果爲:1         2                         1                2  (理解閉包含義)

看完三個實例的時候回頭看下紅字標識閉包的含義:這些外部執行域的非持久型變量神奇地保留他們在閉包最初定義(或創建)時的值。



此文並非深層次解讀,僅爲本人理解。並不能保證完全正確。待以後考究。



發佈了38 篇原創文章 · 獲贊 39 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章