今天在寫代碼之余看了下js閉包,相對於之前的理解又有了稍微深入點的理解。在此分享下我的理解:
本文總共分為五個大的部分:1.理解js閉包前需要理解的js其他慨念。2.js閉包的特性。3.閉包舉例。4.使用js閉包的好處。5.js閉包的用途。6.優化我的js代碼。
1:理解js閉包前需要理解的js其他慨念
a:js的作用域鏈
js作用域鏈:作用域鏈是js函數在創建的時候定義的,用於尋找到變量的一個索引。作用域鏈索引的內部規則是將函數自身的本地變量放在最前面,把自身的父級函數變量放在其次,再把高一級的函數的變量放在更后面,以此類推知道全局對象為止。當需要查找一個變量時,js解釋器會從作用域鏈去查找該變量,先從該函數的本地變量開始查找,如果沒有,則在下一級作用域鏈進行查找,如果查找到相應變量則返回該變量,如果直到最后也沒找到相應變量則返回undefined。
b:js內存回收機制
js的內存回收機制:一個函數在執行開始的時候,會給其中定義的變量划分內存空間保存,以備后面的語句所用,等到函數執行完畢返回了,這些變量就被認為是無用的了,對應的空間也就被回收了。下次再執行此函數的時候,所有的變量又回到最初的狀態,重新賦值使用。但是如果這個函數內部又嵌套了另一個函數(這就是閉包了),而這個函數是有可能在外部被調用到的。並且這個內部函數又使用了外部函數的某些變量的話.這種內存回收機制就會出現問題。如果在外部函數返回后,又直接調用了內部函數,那么內部函數就無法讀取到他所需要的外部函數中變量的值了。所以js解釋器在遇到函數定義的時候會自動把函數和他可能使用的變量(包括本地變量和父級和祖先級函數的變量(自由變量))一起保存起來。也就是構建一個閉包,這些變量將不會被內存回收器所回收,只有當內部的函數不可能被調用以后(例如被刪除了,或者沒有了指針),才會銷毀這個閉包,而沒有任何一個閉包引用的變量才會被下一次內存回收啟動時所回收。
2:js閉包的特性
a:閉包的外層是個函數,閉包內部有函數。
b:閉包會return內部函數,閉包返回的函數內部不能有return。(如果有會結束閉包)
c:執行閉包后,閉包的內部變量會存在,閉包內部函數的內部變量會回收。
3:js閉包舉例
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。由此可知執行閉包后,閉包的內部變量會存在,閉包內部函數的內部變量會回收。
4:使用js閉包的好處
使用閉包有以下幾大好處:
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
5:js閉包的用途
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);
6:優化我的js代碼
在以后的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());