以前發了一篇文章,寫了一些對於閉包的理解。如今補上閉包的應用篇。本文主要分享一些常見的閉包用法和分析,也但願能增長對閉包的理解。javascript
在以前的文章裏,講解了閉包的原理,若是忘記了能夠點擊這裏再看一下,在這裏咱們簡單回顧一些知識點:java
閉包常見的用法,就將圍繞這些特色展開:segmentfault
首先簡單舉個例子來,解釋一下什麼是塊級做用域:閉包
function A(){ for(var i = 0; i < 3; i++){ console.log(i) } console.log(i) // 在循環體外依然能夠讀到i 輸出3 } A();
在這個簡單的函數中,變量i
是在for
循環中定義的,若是是在C++或者Java中,這樣定義的變量,一旦循環結束,變量也就隨之銷燬,i的做用範圍只在循環這個小塊,就稱爲塊級做用域。在javascript中,沒有這樣的塊級做用域,前面一篇文章已經提到,變量是定義在函數的活動對象中的,所以,從定義i
開始,在函數內部能夠隨時訪問它。
這樣的壞處顯而易見:因爲javascript不會告訴你變量是否已經被聲明,容易形成命名衝突,若是是在全局環境定義的變量,就會污染全局環境,所以能夠利用閉包特性來模擬塊級做用域。不過在此以前要先介紹另外一個知識點:匿名當即執行函數。若是已經比較熟悉的同窗能夠直接跳過這一塊:函數
首先舉個例子(我比較喜歡舉例,感受看例子比較更容易理解):this
var helloWorld = function(){ alert('Hello world') } helloWorld();//執行函數
上面的簡短代碼一共就作兩件事:1.定義了一個匿名函數並賦值給helloWorld
;2.在helloWorld
後面加括號表示調用函數,因此 匿名函數若是直接執行,是否是應該這樣寫:code
function(){ alert('Hello world') }()
這樣的寫法會報錯,由於在javascript中,function是函數聲明的標誌,不容許在後面直接加括號,而應該寫成這樣:對象
(function(){ //函數體 alert('Hello world') })()
也就是把聲明部分加括號便可,加了括號之後,這一段代碼就至關於執行了裏面的函數體部分,可是此時內部的變量已經不能被外部訪問,請看下面詳細樣例繼承
如今咱們講模擬塊級做用域的具體步驟,假設仍是針對前面的A函數
,若是咱們想讓i變量只有塊級做用域,能夠這樣寫:ip
function A() { //核心代碼 (function(){ for(var i = 0; i<3; i++) { console.log(i); } })() // 如今,做用域外沒法訪問到i了 console.log(i)//underfined } A();
注意看核心代碼部分,咱們用剛剛講到的匿名自執行函數在內部造成了一個閉包,這個閉包在哪呢?一直強調,閉包的本質是函數,其實在這裏閉包就是那個匿名函數,這個閉包能夠到函數A
內部的活動變量,又能保證本身內部的變量在自執行後直接銷燬,這個應該不難理解了
這種寫法的常常用在全局環境中,能夠避免添加太多的全局變量和全局函數,特別是多人合做開發的時候,能夠減小所以產生的命名衝突等,避免污染全局環境。
咱們知道閉包的另外一個特色是能夠保存外部函數的變量,原理是基於javascript中函數做用域鏈的特色,內部函數保留了對外部函數的活動變量的引用,因此變量不會被釋放(這一塊沒有理解清楚的請看前一篇文章,裏面講的比較詳細),而後咱們再來愉快地舉例子:
function B(){ var x = 100; return { function(){ return x } } } var m = B()//運行B函數,生成活動變量 x被m引用
這是前文介紹過的一個最簡單的閉包例子,咱們運行B函數
,返回值就是B內部的匿名函數,此時m引用了變量x,因此B執行後x不會被釋放,利用這一點,咱們能夠把比較重要或者計算耗費很大的值存在x中,只須要第一次計算賦值後,就能夠經過m函數引用x的值,沒必要重複計算,同時也不容易被修改
這種寫法可能會用在把一些不常常變更,可是計算比較複雜的值保存起來,就能夠節省每次訪問的時間。
javascript中沒有私有成員的概念,咱們能夠把函數當作一個範圍,函數內的變量就是私有變量,在外部沒法引用,好比:
function C(a,b){ var c = a - b ; return c }
在這個函數中,a b c都是私有變量,在外部沒法訪,利用閉包的特色,咱們能夠就能夠建立能夠訪問私有變量的方法:
function Person(){ var name = 'default'; this.getName:function(){ return name; } this,setName:function(value){ name = value; } } console.log(Person.getName())//default console.log(Person.setName('mike')) console.log(Person.getName())//mike
在這個例子中,設置了兩個閉包函數來操做Person函數內部的name變量
,除了這兩個函數,在外部沒法再訪問到name變量,name也就至關因而私有成員。在這個例子中,咱們用的是在構造函數中定義公有方法,對於全部的Person實例,都分別建立了新的辦法,固然還可使用其餘形式來避免這個問題,要涉及到建立對象模式的一些知識,在這裏說明怕反而增長了閉包的理解難度,以後在寫對象和繼承的時候再提到(下一次更新必定不會這樣久了QAQ)。
關於閉包的主要主要應用就講到這裏,本文中不少知識點與上一篇文章有關,又由於發佈相隔時間比較長(個人鍋),建議你們能夠先看看上一篇複習一下,這篇相對來前一篇容易理解,並且在舉例過程儘可能沒有加入其它的疑難知識點,但願能對看到的人有所幫助。以上內容屬於我的看法,若是有不一樣意見,歡迎指出和探討。同時,碼字不易請尊重做者的版權,轉載請註明出處,如做商用,請與做者聯繫,感謝!
若是看完對您有幫助,順手點個推薦唄~