對Javascript閉包的一點點理解

tags:    時間:2013-12-13 21:46:12
我對Javascript閉包的一點點理解

前言

如果前端人員不懂Javascript閉包,那隻能說他壓根就沒懂Javascript,只能算入門級。本篇主要是寫本人對閉包的一些理解,歡迎拍板。

 

閉包概念

先引用一下官方解釋:

 

A "closure " is an expression (typically a function) that can have free varuables together with an environment that binds those variables (that "closes" the expression)

 

用我的蹩腳英語翻譯過來換成自己的理解就是:

 

1.閉包首先是一個表達式,通常這個表達式是一個函數。

2.閉包擁有一個環境,使得它能夠擁有這個環境底下的這個許多變數。

 

閉包舉例

可能上邊解釋還是有點抽象,那我拿實際的代碼舉個例子:

var name = "window"; 			 function outer(){ 	var name = 'outer';  	function inner(){ 		return name; 	}    return inner; }  alert(outer()()); 

 

可以試著在瀏覽器運行一下這段script,會發現,彈出框內容為outer。

我先解釋這個過程大致發生了什麼,再聯繫前面說的兩點說說我對閉包的理解。

首先第一行定義了name變數,很容易理解,name就是屬於當前的瀏覽的頁面吧!(實際name就是在當前window底下的全局變數,至於window是什麼變數,不懂的話就把它當做是當前頁面所在的環境吧)。

第2行-第12行我們定義了outer函數。

再看看第13行發生了什麼,outer()()這是什麼語法???那我們先分解來看吧,outer()一般是幹嘛呢?當然是執行outer函數然後返回一個值咯。那在這裡返回值是什麼呢?inner!好,那就是說outer() == inner,應該同意吧?

於是乎outer()() == inner(),

所以最後alert出來的值將會是inner函數返回的值。

 

亂了亂了,不是說過,在一對括弧{}里算是一個域,在這個域裡邊定義的東西,在離開這個域之後就會被銷毀嗎?

上面這個觀點是對的,但是這個就是javascript閉包強大的地方:它把本來要銷毀的一些變數給挽救回來,繼續放在內存裡邊,讓後邊可以調用這個閉包來獲取這些變數。

 

回到例子上吧,我們在outer函數裡邊定義了inner函數,如果說你最後不把它返回並且複製給變數,這個inner函數就會被銷毀了,但是我們在第13行將它拋出去給外界執行了!!!於是js解釋器知道它被暴露在外頭了,不應該被銷毀,所以就留住它的所在的環境,也就是outer的這個域。裡邊的name也被留下來了。

 

執行outer()之後,我們獲取了剛剛說被暴露在外邊的inner函數了,緊接著執行inner(),於是inner就開始找尋name變數了,我們知道inner所在的環境被嵌套了2層,inner->outer->window,當然啦,按照我們就近原則,我們肯定現在inner裡邊找name變數,發現找不到,於是到outer那個環境去找,此時找到了name,把name返回給inner()調用處alert出來。(這裡可以思考一下腳本找尋變數的過程,就可以知道過多地訪問全局變數會經常要把時間消耗在搜索過程,所以盡量避免過多地訪問全局變數,至於怎麼做,比較簡單的就是採用一個局部變數記錄該全局變數並替換成訪問該局部變數)

 

例子跟概念的聯繫

我簡單的把上述例子跟前面的解釋聯繫起來:

1. 閉包首先是一個表達式,通常這個表達式是一個函數。

    例子中的inner函數就是這麼一個表達式。

2. 閉包擁有一個環境,使得它能夠擁有這個環境底下的這個許多變數。

    inner函數返回並提供給外界調用導致了inner會繼續停留在內存,從而提供了一個環境可以訪問outer裡邊的變數。

 

我的理解

按我理解,可以把閉包以及閉包的用法簡單總結成以下:

1.閉包一般就是函數,並且定義在一個函數裡邊的。當然了,閉包還可以是一個對象的。如下代碼:

function outer(){ 	var name = 'outer';  	return { 		inner:function(){ 			return name; 		} 	};  }  alert(outer().inner());

2.在函數裡邊定義函數不一定是閉包,而是應該將這個函數返回並且賦值給外界或者給外界執行這個閉包。

因為js解釋器要知道到底要不要銷毀域底下的東西,如果它發現外界持有這個閉包的引用,它就不會去銷毀這個環境。

3.閉包允許外界訪問函數裡邊的局部變數,例如outer裡邊的name變數。

4.運用閉包可以儲存函數裡邊的變數,可以避免更多的全局變數定義而污染,我覺得可以簡單的跟面向對象的封裝進行類比。

5.閉包會導致變數跟一些引用停留在內存不被銷毀,將會導致內存消耗。

 

本篇總結

對於Javascript,我認為它的閉包是其精華所在,使它變得更加靈活以及衍生了很多高級功能。關於閉包,網上有很多精彩的講解,這裡只是記錄一下本人的理解,歡迎交流。阮一峰的學習Javascript閉包(Closure) 對閉包的講解很不錯,推薦閱讀一下。

推薦閱讀文章

Bookmark the permalink ,來源:互聯網