做爲一名前端閉包知識點在面試彙總常常問道,工做中也會常常用到,下面講下我本身對閉包的認識,但願對各位有所幫助;在講解閉包以前會先講解一些和閉包有關的一些知識和概念,方便更好的理解閉包;前端
做用域是使用一套嚴格的規則來分辨哪些標識符對那些語法有訪問權限。通俗的講,做用域就是查找變量的地方,做用域能夠分爲動態做用域個靜態做用域;面試
請看例子:緩存
var a=1
function myFun(){
var b=2
console.log(a) //1
console.log(b) //2
}
myFun()
複製代碼
上面代碼定義了一個變量和一個函數,函數執行的時候輸出變量a的值1和變量b的值2,此時有一個全局做用域,在全局做用域內部聲明瞭變量和函數myFun,而在函數內部就造成一個函數做用域,在這個做用域內有變量b值爲2;bash
結合上面的例子咱們在函數內部查找a變量的時候,先在函數做用域中查找,沒有找到,就去上一級的做用域去找,直到找到全局做用域,也就是在查找標識符的過程彙總有一個往外層查找的過程。好像是順着一條鏈條從下往上查找,這條鏈條,咱們就稱之爲做用域鏈。閉包
在尚未接觸到ES6的let、const以前,只有函數做用域和全局做用域,函數做用域確定是在全局做用域裏面的,而函數做用域中又能夠繼續嵌套函數做用域,如圖:函數
最外層的做用域性能
函數做用域是js中最多見的做用域了,函數做用域給咱們最直觀的體會就是,內部函數能夠調用外部函數中的變量。一層層的函數,很直觀的就造成了嵌套的做用域。ui
ES6 提供的let,const方法聲明的標識符都會固定於塊中。常被你們忽略的try/catch的catch語句也會建立一個塊做用域。spa
「詞法做用域是做用域的一種工做模型」, 所謂的詞法做用域就是在你寫代碼時將變量和塊做用域寫在哪裏來決定,也就是詞法做用域是靜態的做用域,編譯階段就可以知道所有標識符在哪裏以及是如何聲明的。設計
《JavaScript高級程序設計》這樣描述:
閉包是指有權訪問另外一個函數做用域中的變量的函數; 《你不知道的JavaScript》這樣描述: 當函數能夠記住並訪問所在的詞法做用域時,就產生了閉包,即便函數是在當前詞法做用域以外執行。
var counter = (function(){
var privateCounter = 0; //私有變量
function change(val){
privateCounter += val;
}
return {
increment:function(){
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return privateCounter;
}
};
})();
複製代碼
var fn=(function(){
var cache={}//將結果緩存到該對象中
return function(){
var str=JSON.stringify(arguments);
if(cache[str]){//判斷緩存中是否存在傳遞過來的參數,存在直接返回結果,無需計算
return cache[str];
}else{//進行計算並返回結果
var sum=0;
for(var i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return cache[str]=sum;
}
}
})()
複製代碼
上面的示例將計算後的結果緩存到局部變量cache當中,在調用這個函數時,先在緩存中查找,若是找不到,則進行計算,而後將結果放到緩存中並返回,若是找到了,直接返回查找到的值。
function init(){
var a = "1";//a是一個被init建立的局部變量
function sayA(){//sayA是一個內部函數,閉包
alert(a);//a
}
sayA();
}
init();//"a"
複製代碼
閉包的缺點就是常駐內存會增大內存使用量,而且使用不當很容易形成內存泄露。
若是不是由於某些特殊任務而須要閉包,在沒有必要的狀況下,在其它函數中建立函數是不明智的,由於閉包對腳本性能具備負面影響,包括處理速度和內存消耗。
能夠讀取函數內部的變量。
可讓這些局部變量保存在內存中,實現變量數據共享。