JavaScript面向對象程序設計(7): 閉包

閉包這個概念看上去很深奧,這個詞在離散數學裏面的意思確實比較難於理解。在這裏,咱們先能夠把閉包理解成是一種匿名函數或者匿名類。
 
1. 什麼是閉包?
 
什麼是閉包?一種正式的解釋是:所謂閉包,指的是一種擁有不少變量而且綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是這個表達式的一部分。
 
相信不少人都不會理解這個定義,由於他的學術味道太濃了——或許你喜歡從字面的語法上進行分析:首先,它是一個表達式,這個表達式綁定了不少變量以及這些變量的環境。不過這並無什麼意義,這依然不會告訴咱們什麼是閉包。
 
那麼,來看一個例子:
 
function add(a) {
         return function(b) {
                 return a + b;
        };
}
var func = add(10);
alert(func(20));
 
我想通過了前面有關函數的描述,這個例子應該很清楚的理解。JavaScript裏面的函數就是對象,他能夠作對象能作的一切事情——咱們首先定義了一個函數add,它接受一個參數,這個函數返回一個匿名函數,這個匿名函數也接受一個參數,而且會返回這個參數同外部函數的那個參數的和。所以在咱們使用的時候,咱們將add返回的匿名函數賦值給func,而後調用func,就返回了這兩個數的和。
 
當咱們建立一個這樣的函數,這個函數內部的一個變量可以在函數外面被引用時,咱們就稱建立了一個閉包。仔細的品味一下:這就是那個閉包的定義。
 
看看咱們的代碼:首先,它有一個內部變量,就是那個匿名函數;其次,這個函數將匿名函數返回了出去,以便外面的變量能夠引用到內部定義的變量。
 
2. 閉包的做用
 
閉包有什麼用呢?或許如今還看不出來,那麼看看這段代碼:
 
function inc(a) {
         var i = 0;
         return function() {
                 return i;
        };
}
var num = inc();
alert(num());
 
原本,這個變量 i 在函數外面是訪問不到的,由於它是 var 定義的,一旦跳出做用域,這個變量就被垃圾回收了,可是,因爲咱們使用了閉包,在外面是可以訪問到這個變量的,所以它並不被垃圾回收!
 
若是仍是不明白閉包的做用,那麼看一段應該很熟悉的代碼:
 
function Person() {
         var id;
         this.getId = function() {
                 return id;
        }
         this.setId = function(newId) {
                id = newId;
        }
}
var p = new Person();
p.setId(1000);
alert(p.getId()); // 1000
alert(p.id); // undefined
 
咱們定義一個類Person,它有一個id屬性。如今這個屬性的行爲很像是私有變量——只能經過 setter 和 getter 函數訪問到。沒錯,這就是閉包的一個用途:製造類的私有變量!
 
閉包還有一個做用:在內存中維護一個變量,不讓垃圾回收器回收這個變量。這裏的例子就再也不舉出了。
 
這裏咱們只是簡單的說了JavaScript的閉包的概念,並無涉及閉包的內存模型等等之類。這是一個至關重要的概念,Java社區中的部分紅員一直對閉包求之不得,C#也已經在最新版本中添加了閉包的概念,只不過在那裏稱爲lambda表達式。
相關文章
相關標籤/搜索