閉包
這篇文章的啓蒙來自與對閉包問題的求解時看的一個知乎回答:閉包(計算機科學)是什麼?
javascript中的閉包
talk is cheap show me the code ,所以先來看個例子
int y=3;
function A(){
int x=2;
return x+y;
}
寫js代碼時我們很自然的就是這麼寫。但是如果是c語言呢
int A();
void main(){
int y=3;
A();
}
int A(){
int x=2;
return x+y;
}
這樣肯定會報錯,我們一般會這樣寫
int A();
void main(){
int y=3;
A(y);
}
int A(y){
int x=2;
return x+y;
}
這樣寫就沒錯了,但是這樣就不是閉包了。因爲傳參的時候參數實際上是把外部的作用域變量的值複製給本作用域變量,也就是參數也是本作用域定義的一個變量。從這裏的區別,能看出要形成閉包,我們必須要使用不是本作用域內定義的變量。javascript允許使用“外面”作用域的變量。原理可以看javascript高級程序設計這本書。所以閉包的概念就是使用不是本作用域的變量,可能這不是很嚴謹,但是能總體概括成這句話。
java中的閉包
接下來看看其他語言的閉包來加深對閉包的理解。
public class A{
public int y;
public int fn(){
int x=2;
return x+y;
}
public static void main(String[] args){
fn();
}
}
這裏就存在閉包了,因爲y不是fn函數的局部變量。y不是傳參複製給fn的局部變量的。這裏y不是fn的局部變量,那麼爲什麼能被訪問呢,其實實際調用應該是這樣的 return x+this.y;
this是指向對象實例的指針。
擴展
上面已經能大概的概括出閉包的概念了,但是還可以更深理解閉包,那麼可以瞭解函數壓棧,棧內存和堆內存。接下來是我自己的總結,不能保證正確,但以後學習更多的知識會來更新自己的總結。
- 棧內存和堆內存
棧內存存放由操作系統分配的靜態內存,函數的局部變量就保存在裏面。
堆內存則存放由代碼申請的內存的,c語言是malloc(sizeof(int)*6),然而我們new對象時也調用了malloc函數,所以對象是存放在堆內存中的。關於棧內存和堆內存可以看看這篇博客 - 函數壓棧
當我們調用函數的時候,我們會在棧內存開闢一段內存出來給我們保存我們的局部變量和返回地址等其他數據。局部變量就包括參數和在函數中定義的變量,所以當我們執行函數裏面的代碼時這些變量就能夠被找到。當執行完函數,這段內存會被出棧,就是沒有指針指向它了,就找不到了。那麼this.y是如何被找到的呢,它不是局部變量(參數或函數內定義的變量),所以那段棧內存是沒有保存y的值。確實是沒有保存y的值,但是那段棧內存保存了this指針(這一點是自己的推測),通過this指針能夠找到存在堆內存的A的對象實例,自然能找到找實例中的y。