不久前的面試中,面試官開門見山問我閉包是什么,我啞然。就像this一樣,可能給我幾道關於this的題目我會做,但是要我說說什么是this,我還真不知道從何說起,為了face以后同樣的問題,查閱了一些資料在此簡單做下記錄。誠然,樓主對於閉包的理解還處在初級階段...
簡單來說閉包擁有三個特性:
1.函數嵌套函數
2.函數內部可以引用外部的參數和變量
3.參數和變量不會被垃圾回收機制回收
閉包是指有權訪問另一個函數作用域中的變量的函數,創建閉包的最常見的方式就是在一個函數內創建另一個函數,通過另一個函數訪問這個函數的局部變量。使用閉包有一個優點,也是它的缺點,就是可以把局部變量駐留在內存中,可以避免使用全局變量。全局變量在每個模塊都可調用,這勢必將是災難性的。(所以推薦使用私有的,封裝的局部變量。)一般函數執行完畢后,局部活動對象就被銷毀,內存中僅僅保存全局作用域。但閉包的情況不同!
我覺得這段說明也很精彩:js里的函數在運行結束之后,所有的過程中產生的變量都會被銷毀(銷毀原則是無引用)
但在js的函數A里定義一個函數B並在外部引用時,這條引用鏈上的變量都不會銷毀(即使A已經運行結束),這個函數B就叫做一個閉包。
function fn() { var a = 0; function f() { console.log(a++); } return f; } var b = fn(); b(); // 0 b(); // 1 b(); // 2
接着來看上面的例子,這是一段經典的閉包代碼,我們看看代碼都干了些什么。
首先要明確f函數即是所謂的閉包,我們看到它嵌套在fn函數內,而且訪問了外部的變量a,同時console的結果也證明了變量a貯存在了內存中!為什么會這樣呢?原因在於f被賦予給了一個全局變量b,導致始終存在在內存中,而f的存在必須依賴於fn,這導致fn也始終存在在內存中,於是變量a不會在執行后被垃圾回收機制回收。以上例子很好地避免了全局變量的使用,避免了全局變量的污染。
閉包還有什么用?繼續一個經典的例子:
<ul> <li>0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> <script> var lis = document.getElementsByTagName('li'); for(var i = 0; i < lis.length; i++) { ~function(i) { lis[i].onclick = function() { alert(i) }; }(i) } </script>
我們都知道不使用閉包的話,每個li彈出的數字會是一樣的,這時的閉包就能把i的值儲存在內存中。
閉包還可用於模塊化代碼,減少全局變量的污染:
var abc = (function(){ //abc為外部匿名函數的返回值 var a = 1; return function(){ a++; alert(a); } })(); abc(); //2 abc(); //3
閉包還可用於設置私有成員:
var obj = function(){ var num = 0; function a() { num++; return num; } function b() { num++; return num; } return { a: a, b: b } }(); console.log(obj.a()); // 1 console.log(obj.b()); // 2
這樣就無法修改num的值了,保護了私有成員。
個人感覺閉包和立即執行函數有着剪不斷理還亂的關系啊...
樓主對於閉包的理解暫時到這里了,如有不對或者補充之處還望留言~