經常被問到什么是閉包?
說實話閉包這個概念很難解釋。JavaScript權威指南里有這么一段話:“JavaScript函數是將要執行的代碼以及執行這些代碼作用域構成的一個綜合體。在計算機學術語里,這種代碼和作用域額綜合體叫做閉包。”。言外之意所有的JavaScript函數都是閉包。
有人會說,這個解釋不對。我們經常說的閉包應該像下面的一串代碼:
var f1 = function(){ var a=1; return function f2(){ a++; alert(a) } } var b = f1(); b(); // 2 b(); // 3
是的,這是閉包中的一個經典例子,也是我們通常說的閉包。在這段代碼中,b便是閉包f2的函數。
為什么使用閉包?
寫到這里,我們不得不先理解下JavaScript的特殊變量作用域和JavaScript的垃圾回收機制了。
(1)、什么是變量作用域呢?一個變量的作用域是程序中第一這個變量的區域。JavaScript的變量分為“全局變量”和“局部變量”。
全局變量:全局變量的作用域是全局性的,即在JavaScript代碼中,它處處都有定義。我經常寫一個“a=1”,這個變量“a”就被定義成了全局性的了。
局部變量:在函數之內聲明的變量,就只在函數體內部定義,它的作用域是局部性的。函數的參數也是局部變量,它們只在函數體內有定義。在函數體內,局部變量的優先級比同名的全局變量要高,例如:
var a =1; function f1(){ var a=2; alert(a); } f1(); // 2
那么如果我把 變量“a”變成局部變量的話,例如:
function f1(){ var a=2; } alert(a);
就會報如下圖的錯誤:
有人會說,怎么 可能會有這么奇葩的需求,下面我舉個例子,大家就會發現,其實我們還是用過的。
閉包實例:
當我“點擊”按鈕時,效果如下:
代碼我們也許會這么處理:
$('.button').click(function(){ var length = $('.list').find('li').length; var timer =null; for(var i=0;i<length;i++){ timer=setTimeout(function(){ if(i>length){ clearInterval(timer); } $('.list li').eq(i).css({'-webkit-transform':'scale('+(i+1)+')','marginLeft':(i+1)*50 +'px'}) console.log(i) },i*2000) } })
運行之后你會發現,並沒有出現我們想要的效果,打印“i”,發現,,怎么會輸出了3次“3”呢,其實是for()里面的變量i的作用域問題,i的作用域僅在for循環的函數體內,怎么才能實現這個效果呢,我們可以做個小的改動,代碼如下:
$('.button').click(function(){ var length = $('.list').find('li').length; var timer =null; for(var i=0;i<length;i++){ timer=setTimeout((function(i){ if(i>length){ clearInterval(timer); } $('.list li').eq(i).css({'-webkit-transform':'scale('+(i+1)+')','marginLeft':(i+1)*50 +'px'}) //console.log(i) })(i),i*2000) } })
把“i”,當做參數傳進去,這便構成了閉包。
(2)、什么是JavaScript的垃圾回收機制呢?
答:JavaScript不要求手動的釋放內存,它使用一種稱為垃圾收集的方法,JavaScript的解釋器可以檢測到何時程序不再使用一個對象了。當它確定了,一個對象是無用的時候,JavaScript的解釋器就把該對象所占用的內存釋放掉了。
所以綜上所述,就不難理解,在f1函數里定義一個局部變量a,在f1函數外面,變量a會找不到,因為,它被釋放掉了。
我們是不是可以這么認為“閉包的作用(或者定義)就是使私有的變量(也可以理解為局部變量)能夠被多個函數共享,而不被JavaScript的解析器自動的從內存中釋放掉”
閉包的缺點:由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
樓樓不才,對閉包的理解目前就這么多,等深入學習了,會再補充和修正的。推薦大家可以看看“阮一峰”老師寫的“學習Javascript閉包(Closure)”,鏈接:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html