JavaScript的閉包特性

 

       閉包是一個比較抽象的概念,尤爲是對js新手來講。在這裏,我就我我的的理解j簡單談一下:安全

     閉包:官方解釋是一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。然而,當我看到這個官方解釋的時候頓時就以爲不通常,這個解釋太學術了,沒達到必定境界的人是理解不了其中深層次內涵的。爲此,咱們將舉出實例來初步說明js中的閉包特性。在瞭解閉包特性以前,咱們須要補充瞭解變量的做用域。閉包

1、變量的做用域函數

       在JS當中一個變量的做用域(scope)是程序中定義這個變量的區域。變量分爲兩類:全局(global)變量和局部變量。其中全局變量的做用域是全局性的,即在JavaScript代碼中,它到處都有定義。而在函數以內聲明的變量,就只在函數體內部有定義。它們是局部變量,做用域是局部性的。函數的參數也是局部變量,它們只在函數體內部有定義。spa

       咱們能夠藉助JavaScript的做用域鏈(scope chain)更好地瞭解變量的做用域。每一個JavaScript執行環境都有一個和它關聯在一塊兒的做用域鏈。這個做用域鏈是一個對象列表或對象鏈。當JavaScript代碼須要查詢變量x(以下圖)的值時(這個過程叫作變量解析(variable name resolution)),它就開始查看該鏈的第一個對象。若是那個對象有一個名爲x的屬性,那麼就採用那個屬性的值。若是第一個對象沒有名爲x的屬性,JavaScript就會繼續查詢鏈中的第二個對象。若是第二個對象仍然沒有名爲x的屬性,那麼就繼續查詢下一個對象,以此類推。若是查詢到最後(指頂層代碼中)不存在這個屬性,那麼這個變量的值就是未定義的。.net

     

例子1:js中的全局變量,結果爲50       例子2:js中的局部變量,結果報錯,緣由就                                                              是函數中的局部變量在外部是不能被引用      prototype

           

      例子3:看看下面代碼,初一看好像結果是50,可是結果確實undefinde,咱們來解釋說明下爲何是undefind----->對象

      做用域鏈圖中很明確的表示出:在變量解析過程當中首先查找局部的做用域,而後查找上層做用域。在例子1中的函數當中沒有定義變量i,因而查找上層做用域(全局做用域),進而進行輸出其值。可是在例子2中的函數內定義了變量i(不管是在alter以後仍是以前定義變量,都認爲在此做用域擁有變量i),因而再也不向上層的做用域進行查找,直接輸出i。然而在例子3中,函數內部依然定義了變量i,因而不會去查找全局做用於,然而不幸的是此時的局部變量i並無賦值,因此輸出的是undefined。blog

                               

2、閉包的概念ip

    上面官方解釋比較學術,我我的比較贊成下面這個說法——>即函數定義和函數表達式位於另外一個函數的函數體內。並且,這些內部函數能夠訪問它們所在的外部函數中聲明的全部局部變量、參數和聲明的其餘內部函數。當其中一個這樣的內部函數在包含它們的外部函數以外被調用時,就會造成閉包。也就是說,內部函數會在外部函數返回後被執行。而當這個內部函數執行時,它仍然必需訪問其外部函數的局部變量、參數以及其餘內部函數。這些局部變量、參數和函數聲明(最初時)的值是外部函數返回時的值,但也會受到內部函數的影響。-----我的理解就是:閉包是可以讀取其餘函數內部變量的函數,即在外面能夠調用函數中的函數的變量,其實他就是將函數內外部鏈接起來的橋樑。內存

以下面例子4:

這段代碼有如下兩個特色:

     一、函數b嵌套在函數a內部;二、函數a返回函數b;

引用關係以下圖:

 

          jsclosure

      這樣在執行完var c = a()後,變量c其實是指向了函數b,b中用到了變量i,再執行c()後就會彈出一個窗口顯示i的值(第一次爲1)。這段代碼其實就建立了一個閉包,爲何?由於函數a外的變量c引用了函數a內的函數b,就是說:

   當函數a的內部函數b被函數a外的一個變量引用的時候,就建立了一個咱們一般所謂的「閉包」。

 

      當函數b執行的時候亦會像以上步驟同樣。所以,執行時b的做用域鏈包含了3個對象:b的活動對象、a的活動對象和window對象,以下圖所示:

          http://www.felixwoo.com/wp-content/uploads/attachments/200712/11_110522_scopechain.jpg

如圖所示,當在函數b中訪問一個變量的時候,搜索順序是:

  1. 先搜索自身的活動對象,若是存在則返回,若是不存在將繼續搜索函數a的活動對象,依次查找,直到找到爲止。
  2. 若是函數b存在prototype原型對象,則在查找完自身的活動對象後先查找自身的原型對象,再繼續查找。這就是Javascript中的變量查找機制。
  3. 若是整個做用域鏈上都沒法找到,則返回undefined。

3、閉包的用途及優點

(一)、用途

     一、閉包能夠讀取函數內部變量    二、將函數內部變量的值始終保存在內存中

例子5:

      這個例子中的result實際上就是閉包函數b,他一共運行兩次,第一次值99,第二次值爲100,這就說明i一直在內存中,而不是在第一次a函數調用以後就自動清除。另外還需注意iAdd=function(){i++;},這裏iAdd是全局變量,且它的值爲匿名函數,其實也是一個閉包。

(二)、優點

 

 一、保護函數內的變量安全。以最開始的例子爲例,函數a中i只有函數b才能訪問,而沒法經過其餘途徑訪問到,所以保護了i的安全性。

 

 

 

 二、在內存中維持一個變量。依然如前例,因爲閉包,函數a中i的一直存在於內存中,所以每次執行c(),都會給i自加1。

 

 三、經過保護變量的安全實現JS私有屬性和私有方法(不能被外部訪問)。

 

原文地址:http://my.oschina.net/longteng2013/blog/156782

相關文章
相關標籤/搜索