閉包和匿名函數

想要學習閉包先來看看什麼是匿名函數吧!  
(一)匿名函數  
     匿名函數就是沒有名字的函數。他有兩種聲明方式:  
     1.典型的函數聲明:        function functionName(arg0,arg1,arg2){            //函數體        }        2.函數表達式:        var functionName = function(arg0,arg1,arg2){            //函數體        }   雖然這兩種方式在邏輯上市等價的,可是他們仍是存在區別的。   區別1:前者會在代碼執行之前被加載到做用域中,然後者則是在代碼執行到那一行的時候纔會有意義。   區別2:前者會給函數指定一個名字,然後者則是建立一個匿名函數,而後將這個匿名函數賦給一個變量。          換句話說上面第二個例子:建立了一個帶有3個參數的匿名函數,而後把這個匿名函數賦給了變量functionName,並無給匿名函數指定名字。   (二)閉包   書上定義是這麼說的:指有權訪問另外一個函數做用域中的變量的函數   但是這種說法令新手難以理解。其實,在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。           1.那我先來講說爲何要有閉包這麼個概念吧,它產生的意義是什麼呢?        (1)首先咱們學過前面的做用域了,知道了一個概念:函數內部能夠直接讀取全局變量。        那麼看代碼:        var n=999;      function f1(){       alert(n);      }      f1(); // 999        (2)而後另一個概念:在函數外部天然沒法讀取函數內的局部變量         那麼再看代碼:        function f1(){       var n=999;      }      alert(n); //輸出錯誤        (3)這裏有一個地方須要注意,函數內部聲明變量的時候,必定要使用var命令。若是不用的話,你實際上聲明瞭一個全局變量!(咱們之前也提到過的!)        function f1(){       n=999;      }      f1();      alert(n); // 999        下面關鍵的來了!:那就是如何從外部讀取局部變量呢?         那就是在函數的內部,再定義一個函數。(也就是閉包!!)         function f1(){           var n=999;          function f2(){             alert(n); // 999          }        }        在上面的代碼中,函數f2就被包括在函數f1內部,這時f1內部的全部局部變量,對f2都是可見的。可是反過來就不行,f2內部的局部變量,對f1就是不可見的。既然f2能夠讀取f1中的局部變量,那麼只要把f2做爲返回值,咱們不就能夠在f1外部讀取它的內部變量了嗎!來看代碼:        function f1(){           var n=999;          function f2(){             alert(n);          }              return f2;        }          var result = f1();          result(); //999   這段代碼與上面的不一樣點就是把f2函數做爲了一個返回值,而後在調用它。這時你確定在想最後兩行什麼意思啊?其實開始我也沒鬧明白,通過高人指點,其實這最後兩行的意思就是要調用f2這個函數的返回值。這兩行若是我改寫一下是否是更容易明白了呢?        var result = f1();        result();        合併成爲:f1()();其實結果是同樣的        也能夠更好的說明f2這個閉包的做用是:經過把它做爲返回值(由於它能訪問函數f1內的局部變量),而後從全局環境中調用這個返回值,這樣天然就達到了咱們的目的---從全局做用域中讀取局部函數內的變量!        2.既然知道了閉包的意義,下面就來了解下閉包的用途吧!        (1)閉包的第一個用途,其實上面已經提到了,就是產生它意義:能夠讀取函數內部的變量        (2)閉包的第二個用途,那就是:可讓這些變量的值始終保持在內存中        第二個用途怎麼理解呢?來看代碼:        function f1(){            var n=999;            nAdd=function(){                n+=1            }            function f2(){          alert(n);        }            return f2;       }        var result=f1();   //把f1函數的返回值(而這個返回值是函數f2的形式)給result        result();          // 999   輸出這個f2的返回值        nAdd();            //調用nAdd函數        result();          // 1000  這裏就是閉包的第二個用途:f2這個閉包會讓變量n的值始終保存在內存中   光靠代碼來理解第二種用途,好像沒有什麼說服力,下面就用畫圖的方法來讓你們更深入的理解!!              第二種用途其實就和做用域鏈產生聯繫了,我來解釋下:   閉包f2從f1函數中被返回後,它的做用域鏈被初始化爲包含f1函數的活動對象和全局變量對象(黑線部分)。這樣f2就能夠訪問在f1()函數中定義的全部變量。更爲重要的是就算f1()被執行完畢後,它的活動對象也不會被銷燬,由於如圖f2這個閉包還在引用f1函數的活動對象,這也就是爲何上述第二種用途的緣由:閉包會讓變量始終保存在內存中,直到閉包被摧毀。
相關文章
相關標籤/搜索