JavaScript設計得最出色的就是它的函數的實現,它幾乎接近於完美。咱們如今現就來介紹它其中一個功能「閉包」。咱們能夠利用閉包「保存變量生命週期」和「屏蔽變量」的特性優雅地完成一些強大的功能。後面我還會介紹在ExtJS中是如何使用這種特性的。數組
咱們能夠利用「閉包」功能來實現隱藏或公開對象的變量和方法。服務器
測試代碼以下閉包
1 var bufferObj = (function createFun(fn, interval, scope) { 2 var isExec = 1;//被閉包的變量,外界不能直接訪問 3 return {//公開set,和exec方法 4 set : function(data) { 5 isExec = data; 6 }, 7 exec : function(fn) { 8 if (isExec) {//讀取閉包的變量 9 console.log("函數能夠執行"); 10 fn(); 11 } else { 12 console.log("函數不能執行"); 13 } 14 } 15 }; 16 })();
注意咱們把整個函數用括號包住,並在最後一行加了"()",這樣寫法的意思是立刻執行函數,並返回告終果值。這樣咱們的變量「bufferObj」對象就是帶有公開的set和exec方法和私有變量「isExec」。我不能直接訪問到「isExec」這個變量,這就是咱們使用閉包的結果,將一些變量或方法優雅的變成私有,很好的控制了變量的做用域。app
上節初步的說明了閉包的寫法和功能,看似功能不過如此,其實否則。下面咱們來看看ExtJs是如何使用閉包功能的,但願能夠給你們在使用閉包有更多的啓發。這也是學習JS這門語言有興趣的地方,是把一個簡簡單單的知識點寫出多種花樣。函數
下面的代碼是extjs中「Ext.Function」類中的「createBuffered」方法,主要功能就是生成「帶有延遲功能的函數」。我爲了簡化「Ext.Function」類的上下文,並把代碼標上的漢語解釋方便講解。學習
Ext.Function 代碼以下:測試
1 var Ext = {}; 2 Ext.Function = { 3 /** 4 * 返回帶有延遲功能的函數,若是在延遲的時間內再次調用該函數,重置緩衝時間 5 * @param {Function} fn 須要被延遲的方法 6 * @param {Number} buffer 延遲時間(毫秒) 7 * @param {Object} [scope=this] 傳入方法的做用域 8 * @param {Array} [args] 方法參數 9 * @return {Function} 返回帶有緩衝功能的函數 10 */ 11 createBuffered: function(fn, buffer, scope, args) { 12 var timerId;//計時器ID 13 14 return function() { 15 var callArgs = args || Array.prototype.slice.call(arguments, 0),//將「arguments」類型轉成數組類型 16 me = scope || this;//若是沒有傳入「scope」參數就全用當前上下文的"this"爲做用域 17 18 if (timerId) {//若是有計時器,就取消以前的計時器 19 clearTimeout(timerId); 20 } 21 22 timerId = setTimeout(function(){//重置緩衝時間 23 fn.apply(me, callArgs);//在相應的做用域上執行方法 24 }, buffer); 25 }; 26 } 27 };
在上述代碼中把變量「timerId」閉包在對象內,只返回了一個帶有緩衝功能的方法,該返回方法主要是判斷函數在緩衝期內是否被重複調用,若是在緩衝期內被調用就重置計時器。this
在代碼中有三個知識點:spa
1. 15行中「Array.prototype.slice.call(arguments, 0)」這句意思是把arguments參數類型轉成數組類型,方便第23行的「apply」調用。(若是不知道arguments是什麼意思的同窗就自行面壁思過吧,哈哈哈。)prototype
2. 16行中"me = scope || this" ,是一個if判斷取巧的寫法。整句的意思是,當「scope」爲「空」或「假」時就把「this」返回給「me」變量。
3. 18行中的「timerId」變量因爲是被閉包,他的「生命期」被延長了,不會隨着返回函數的運行結束而結束,因此每次調用返回函數時,均可以保留以前的「timerId」值。
使用代碼以下:
1 var run = function(data) { 2 alert("函數運行成功"); 3 alert("入參爲:" + data); 4 }; 5 var bufferFn = Ext.Function.createBuffered(run, 3000); 6 bufferFn("JavaScript1");//不會被執行,由於後一個函數在緩衝期3秒內調用,把這當前的函數取消了 7 bufferFn("JavaScript2");//不會被執行,由於後一個函數在緩衝期3秒內調用,把這當前的函數取消了 8 bufferFn("JavaScript3");//會被執行,由於後一個函數沒有在緩衝期3秒內調用,因此該函數會執行 9 10 setTimeout(function() {//間隔4秒 11 bufferFn("JavaScript4");//會被執行,由於後面沒有重複調用了 12 }, 4000);
在上述代碼第5行,就是經過「Ext.Function.createBuffered」生成了一個帶有緩衝功能的函數「bufferFn」,若是咱們在3秒的緩衝期內重複調用就不會重複執行函數。