閉包是一個比較抽象的概念,尤爲是對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;
引用關係以下圖:
這樣在執行完var c = a()後,變量c其實是指向了函數b,b中用到了變量i,再執行c()後就會彈出一個窗口顯示i的值(第一次爲1)。這段代碼其實就建立了一個閉包,爲何?由於函數a外的變量c引用了函數a內的函數b,就是說:
當函數a的內部函數b被函數a外的一個變量引用的時候,就建立了一個咱們一般所謂的「閉包」。
當函數b執行的時候亦會像以上步驟同樣。所以,執行時b的做用域鏈包含了3個對象:b的活動對象、a的活動對象和window對象,以下圖所示:
如圖所示,當在函數b中訪問一個變量的時候,搜索順序是:
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