今天在寫代碼之餘看了下js閉包,相對於以前的理解又有了稍微深刻點的理解。在此分享下個人理解:數據庫
本文總共分爲五個大的部分:1.理解js閉包前須要理解的js其餘慨念。2.js閉包的特性。3.閉包舉例。4.使用js閉包的好處。5.js閉包的用途。6.優化個人js代碼。json
js做用域鏈:做用域鏈是js函數在建立的時候定義的,用於尋找到變量的一個索引。做用域鏈索引的內部規則是將函數自身的本地變量放在最前面,把自身的父級函數變量放在其次,再把高一級的函數的變量放在更後面,以此類推知道全局對象爲止。當須要查找一個變量時,js解釋器會從做用域鏈去查找該變量,先從該函數的本地變量開始查找,若是沒有,則在下一級做用域鏈進行查找,若是查找到相應變量則返回該變量,若是直到最後也沒找到相應變量則返回undefined。緩存
js的內存回收機制:一個函數在執行開始的時候,會給其中定義的變量劃份內存空間保存,以備後面的語句所用,等到函數執行完畢返回了,這些變量就被認爲是無用的了,對應的空間也就被回收了。下次再執行此函數的時候,全部的變量又回到最初的狀態,從新賦值使用。可是若是這個函數內部又嵌套了另外一個函數(這就是閉包了),而這個函數是有可能在外部被調用到的。而且這個內部函數又使用了外部函數的某些變量的話.這種內存回收機制就會出現問題。若是在外部函數返回後,又直接調用了內部函數,那麼內部函數就沒法讀取到他所須要的外部函數中變量的值了。因此js解釋器在遇到函數定義的時候會自動把函數和他可能使用的變量(包括本地變量和父級和祖先級函數的變量(自由變量))一塊兒保存起來。也就是構建一個閉包,這些變量將不會被內存回收器所回收,只有當內部的函數不可能被調用之後(例如被刪除了,或者沒有了指針),纔會銷燬這個閉包,而沒有任何一個閉包引用的變量纔會被下一次內存回收啓動時所回收。閉包
a:閉包的外層是個函數,閉包內部有函數。函數
b:閉包會return內部函數,閉包返回的函數內部不能有return。(若是有會結束閉包)優化
c:執行閉包後,閉包的內部變量會存在,閉包內部函數的內部變量會回收。spa
1 function outerFun(){ 2 var myVal=0; 3 function innerFun(){ 4 alert(++myVal); 5 } 6 return innerFun; 7 } 8 var myFun = outerFun(); 9 myFun();myFun();
此js代碼在執行的過程當中分別alert出1,2。由此可知執行閉包後,閉包的內部變量會存在,閉包內部函數的內部變量會回收。指針
使用閉包有如下幾大好處:code
a:但願一個變量長期駐紮在內存中。對象
b:避免全局變量的污染。
var abc = (function(){ //abc爲外部匿名函數的返回值 var a = 1; return function(){ a++; alert(a); } })(); abc(); //2 ;調用一次abc函數,實際上是調用裏面內部函數的返回值 abc(); //3
c:私有成員的存在。
var aaa = (function(){ var a = 1; function bbb(){ a++; alert(a); } function ccc(){ a++; alert(a); } return { b:bbb, //json結構 c:ccc } })(); aaa.b(); //2 aaa.c() //3
a:匿名自執行函數。
(function(){ alert("已進入就執行"); })();
咱們建立了一個匿名的函數,並當即執行它,因爲外部沒法引用它內部的變量,所以在執行完後很快就會被釋放,關鍵是這種機制不會污染全局對象。
b:使用閉包對數據進行緩存。
在咱們作項目的時候,常常遇到一些數據很是大且沒有必要進行及時查詢的數據。以下拉框數據等。那麼在此時咱們能夠在啓動應用的時候在頁面將這些數據進行緩存起來,若是緩存中有咱們須要的數據則直接讀緩存,若是緩存中沒有咱們須要的數據,則進行查詢數據庫。閉包能夠爲咱們作到這點。
var CachedSearchData = (function () { var cacheData = [], count = cacheData.length; return { getSearchData: function (id) { if (id in cacheData) {//若是結果在緩存中 return cacheData[id];//直接返回緩存中的對象 } else { //到數據庫中查找 alert("search in database"); } }, clearSearchData: function (id) { if (dsid in cache) { cache[dsid].clearSelection(); } } }; })(); CachedSearchData.getSearchData(77);
在之後的js代碼中可以使用閉包進行優化一些代碼。
var person = function(){ //變量做用域爲函數內部,外部沒法訪問 var name = "default"; return { getName : function(){ return name; }, setName : function(newName){ name = newName; } } }(); alert(person.name);//直接訪問,結果爲undefined alert(person.getName()); person.setName("zhangsan"); alert(person.getName());