JavaScript 閉包的理解

在瞭解閉包之前,我們先來了解下局部變量全局變量

局部變量
即爲定義在局部作用於下的變量,僅在這個作用域下被調用;


全局變量
即爲定義在window下,在任何地方都可以調用。

那麼他們有哪些優缺點呢?
局部變量用完會隨着當前程序一同被銷燬,不會佔用內存,但是不可以重複使用。
全局變量可以重複使用,但是很容易造成變量污染。
看來局部變量和全局變量都有他的優缺點,
那麼怎麼樣才能夠變量重用,又可以保護變量不會被污染的一種機制呢?
答案當然是有的,這就是今天要介紹的內容 閉包

什麼是閉包(closure)?

首先我們來看看分別在百度百科,菜鳥教程,W3Cschool和ECMAScript中對閉包的描述。

百度百科
閉包就是能夠讀取其他函數內部變量的函數。

菜鳥教程
閉包是一種保護私有變量的機制,在函數執行時形成私有的作用域,保護裏面的私有變量不受外界干擾。 直觀的說就是形成一個不銷燬的棧環境。

W3Cschool
JavaScript 變量可以是局部變量或全局變量。
私有變量可以用到閉包。

ECMAScript
閉包,指的是詞法表示包括不被計算的變量的函數,也就是說,函數可以使用函數之外定義的變量。

綜上所述,閉包就是外層函數的內層函數可以使用外層函數的變量。
怎麼去理解這句話呢?
我們都知道,一般函數在執行完後會出棧,但是閉包導致作用域鏈不被釋放,所有內層函數即使在外層函數執行完成後仍然可以訪問外層函數裏的變量。

function test(){
	var a = 100;
	return function (){
		console.log(a);
	}
}
var result = test();
result();

如上代碼所示,代碼在預編譯GO存在testresulttest 指向function test(){...}函數體,resultundefined,當函數test()執行時,testAO存在a,執行後a的值100,在GO中的result賦值爲function(){console.log(a)},此時test出棧,但是因爲test內變量aresult所引用,所以testAO無法被釋放,result可以訪問到testAO內的值,其中a爲受保護的變量。

閉包在開發中有什麼作用?

在開發中我們會經常的使用動態添加點擊事件,我們按照思維通常會寫成下面這樣

function test(){
	var liList = document.getElementsByTagName("li");
	for(var i = 0; i < liList.length;i++){
		liList[i].onclick = function(){
			console.log(i);
		}
	}
}
test()

但是因爲我們在外層函數裏使用了內層函數,並且使用了外層函數的變量i,形成了閉包
內層函數每一次循環都可以調用外層函數的值並且每次自增1,而點擊事件返回的函數體,此時並沒有去執行;
當我們觸發點擊事件時,此時外層函數的iliList.length,則每一次點擊的iliList.length,與我們預想的結果不同。

怎麼去解決閉包所帶來的問題?

閉包無非就是返回的函數內受保護的變量沒有被放入返回的函數體內,只是返回了函數的內容,那麼我們只需要讓他返回具體的值。

function test(){
	var liList = document.getElementsByTagName("li");
	for(var i = 0; i < liList.length;i++){
		(function(j){
			liList[j].onclick = function(){
				console.log(j);
			}
		}(i))
	}
}
test()

如上代碼所示,i是變化的,但是隻能返回i,不能返回i的值;我們定義一個匿名的函數,講i的值傳入這個匿名函數,則每次返回的爲console.log(1);console.log(2)......

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章