閉包那些事

今天在面試的時候被問到閉包,自己我的感受仍是挺懂的,一時半會忽然又懵逼不知道從何提及(WTF). 好吧那我接下來在從新記錄下吧:git

其餘時效優質文章,歡迎查閱github

專業名詞解釋:

在計算機中,閉包指引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在。

侷限自定義: 在Javascript 中子函數中使用了其父函數或者外層函數的變量等就產生了一個閉包。這時外層變量的值能被子函數使用且外層變量在子函數未銷燬以前一直被分配不會被釋放。面試

說源頭提及:

閉包的產生因爲變量做用域鏈引發的(由詞法做用域致使)。
 微信

JavaScript做用域:

在ES5及以前的語言規範中做用域分3種:閉包

  • 全局做用域
  • 局部(函數做用域)
  • eval做用域。

[注意:沒有塊級做用域]函數

在函數中定義的變量,就屬於局部做用域,且只對函數範圍內其餘表達式可見。
而函數內部又可使用父函數中的變量這就是因爲做用域鏈,當JavaScript查找與變量關聯的值時,會遵循一個查找鏈。這個鏈是基於做用域的層次結構。 以下代碼:spa

var a = "global variable"; 
( function () { 
    console.log(a); 
    var fn = function () { 
        var a = "local variable" 
        console.log(a);
    }     
    fn(); 
})()

//輸出
//global variable
//local variable

咱們在window全局對象下聲明瞭變量a,隨後調用了一個當即執行函數,其中向控制檯直接打印變量a,因爲當即執行函數沒有聲明局部變量a因此致使JavaScript向其做用域鏈繼續查找接着就在window對象中找到a變量並打印出它的值"global variable"。接着這個當即執行函數聲明瞭一個局部函數變量再調用它,在這個函數變量中首先聲明瞭一個局部變量a而後在向控制檯輸出a得值。JavaScript在執行時因爲在fn函數做用域內部查找到了變量a就直接使用變量a的值因此打印出了local variable。code

值得注意的是:對象

  1. 這裏其實有2個閉包環境一個是window對象和當即執行函數所建立的閉包;另外一個是當即執行函數和其內部聲明的函數變量fn建立的閉包。
  2. 閉包其實就是個稱呼,重要的是在這種場景下內部函數能夠調用外部函數的變量,而這正是由於詞法做用域鏈。
  3. 當閉包產生,在局部函數未被釋放以前,被引用外部函數的變量就沒法被釋放。

清楚做用域的含義了嗎???索引

那麼咱們剛剛說的「詞法「做用域又是什麼。
其實詞法就是指代環境:因爲函數決定做用域,而且函數是一等公民能夠直接用來參數傳遞等。那麼做用域鏈是怎樣來肯定的呢: 下面的話背熟了:
做用域鏈是根據函數定義時候的位置肯定的而不是在調用時。--這就是「詞法」做用域

若是你還不懂閉包我TM。。。

最後咱們來看看幾個老生長談的基本栗子:

  • [閉包的影響]對一些li綁定點擊事件並打印其索引,對比2斷代碼不解釋:
var liListlength = 3; 
for(var i=0;i<liListlength;i++){ 
    var ele=document.querySelectorAll(".test > li")[i]; 
    ele.addEventListener("click",function(){ 
        alert("index is :" + i); 
    })         
}

var liListlength = 3; 
for(var i=0;i<liListlength;i++){ 
    var ele=document.querySelectorAll(".test > li")[i]; 
    ele.addEventListener("click",(function(i){ 
        return function(){ 
            alert("index is :" + i); 
        } 
    })(i))     
}
  • [閉包的妙用]模擬封裝

咱們能夠運用閉包模擬模塊的實現,即咱們能夠只暴露方法接口隱藏局部變量,具體以下:

var countMoudle = (function(){ 
var _count = 0; 

var plus = function(){ 
  _count++; 
}; 

var minus = function(){ 
  _count--; 
}; 

var print = function(){ 
    console.log(_count); 
} 

return { 
  plus: plus, 
  minus: minus, 
  print: print 

}; 
})();

countMoudle.print()  //0
countMoudle.plus()   
countMoudle.print()  //1
countMoudle.minus()
countMoudle.print()  //0

此時咱們只暴露出了方法名而沒有暴露出變量屬性,這時要對變量的修改只有經過接口方法調用。

最後

若有任何問題和建議歡迎發送至郵箱討論:<Tommy.White.h.li@gmail.com>
編寫不易,若您以爲對您有幫助,歡迎打賞

微信:圖片描述

支付寶:圖片描述

相關文章
相關標籤/搜索