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

閉包這個概念看上去很深奧,這個詞在離散數學裏面的意思確實比較難於理解。在這裏,咱們先能夠把閉包理解成是一種匿名函數或者匿名類。閉包

 

1. 什麼是閉包?函數

 

什麼是閉包?一種正式的解釋是:所謂閉包,指的是一種擁有不少變量而且綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是這個表達式的一部分。this

 

相信不少人都不會理解這個定義,由於他的學術味道太濃了——或許你喜歡從字面的語法上進行分析:首先,它是一個表達式,這個表達式綁定了不少變量以及這些變量的環境。不過這並無什麼意義,這依然不會告訴咱們什麼是閉包。spa

 

那麼,來看一個例子:對象

 

function add(a) { 
        return function(b) { 
                return a + b; 
        }; 

var func = add(10); 
alert(func(20));
ip

 

我想通過了前面有關函數的描述,這個例子應該很清楚的理解。JavaScript裏面的函數就是對象,他能夠作對象能作的一切事情——咱們首先定義了一個函數add,它接受一個參數,這個函數返回一個匿名函數,這個匿名函數也接受一個參數,而且會返回這個參數同外部函數的那個參數的和。所以在咱們使用的時候,咱們將add返回的匿名函數賦值給func,而後調用func,就返回了這兩個數的和。內存

 

當咱們建立一個這樣的函數,這個函數內部的一個變量可以在函數外面被引用時,咱們就稱建立了一個閉包。仔細的品味一下:這就是那個閉包的定義。作用域

 

看看咱們的代碼:首先,它有一個內部變量,就是那個匿名函數;其次,這個函數將匿名函數返回了出去,以便外面的變量能夠引用到內部定義的變量。get

 

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表達式。

>>>>閱讀全文

相關文章
相關標籤/搜索