閉包和一部電影的關係

閉包的定義

在網上,關於閉包的文章衆多。javascript

MDN文檔中說:java

閉包是函數和聲明該函數的詞法環境的組合git

不少文章中說:github

閉包是指有權訪問另外一個函數做用域中的變量的函數閉包

還有一篇文章,總結了閉包的四種定義。函數

最後,我決定去請教個人一個經驗豐富的同事。spa

他說:code

閉包就是閉着的包子對象

......blog

我發現閉包的最大難點,就是沒有一個明確的定義。

因而,我去其精華、取其糟粕,寫下這篇關於閉包但徹底不去定義閉包的文章。

做用域和變量對象

function outter(){
    var name = '小強'
    function inner(){
        console.log(name)
    }
    return inner
}
var foo = outter()
foo()   // '小強'

上面這段代碼,就是一個閉包。

不管閉包的定義是什麼,這段代碼基本上是通行的

首先,若是套用這個定義:

閉包是指有權訪問另外一個函數做用域中的變量的函數

那麼,函數 inner 就是閉包,由於咱們知道:

定義在函數內部的函數,是能夠訪問外部函數的做用域的。

簡寫一下:

function outter(){
    var name = '小強'
    function inner(){
        console.log(name)
    }
    inner()
}

這種結構下, inner函數仍是有權訪問 outter 函數做用域中的變量的,因此這是否是閉包?

(歡迎討論)

上面代碼,是一種最多見的函數嵌套。

當 outter函數執行時,會建立一個屬於 outter的執行環境及變量對象。

當 inner函數執行時,又會建立一個 inner的執行環境及變量對象。

它們的相同點是:

執行完畢以後,各自的執行環境及變量對象都會被銷燬。

儘管函數是一等公民,可是它們執行完畢後、變得「沒用」,JS很快將它們「滅門」,這就是JS垃圾回收機制。

它們的聯繫是:

 inner函數能夠訪問到 outter函數的變量對象。

變量對象,顧名思義,就是保存該函數自身變量的一個對象。

內部函數保存全部外層函數的變量對象,造成了本身的做用域。

即 inner函數的做用域,包括自身的變量對象、 outter的變量對象和window的變量對象。

爲何要保存別人的變量對象?

由於對本身有用,自身沒有的話就能夠去用外層的。

能夠說,外層函數的變量服務於內部函數。

閉包中的變量對象

再回到這種形式:

function outter(){
    var name = '小強'
    function inner(){
        console.log(name)
    }
    return inner
}
var foo = outter()
foo()   // '小強'

不一樣於普通嵌套,

這裏當 outter函數執行到最後時,將 inner函數return了出去。

顯然, outter已經執行完畢了,可是它的執行環境及變量對象都被銷燬了嗎?

並非。

有一個倖存者,就是outter函數的變量對象

雖然 outter函數在return以後,自身已經執行完畢。

可是,由於它return的是嵌套在本身內部的函數 inner,並賦值給全局變量 foo ,這就致使:

  • 一方面, outter函數執行完畢, outter的變量對象理應被銷燬

  • 另外一方面, inner函數被賦值給全局變量,隨時有可能被調用,那它的做用域不該該被破壞,其中的 outter變量對象也就不應被銷燬

上面已經說過:

內部函數保存全部外層函數的變量對象,造成了本身的做用域

因此,就是由於還有用,因此 outter函數的變量對象並無在 outter執行後被銷燬,成爲倖存者。

最終,當我執行 foo() 的時候,

儘管 outter函數早已執行完畢,但依然能夠打印出其變量name的值'帥哥小強'。

閉包和一部電影的關係

而我想到的,是《辛德勒名單》這部電影。

1939年,波蘭在納粹德國的統治下,黨衛軍對猶太人進行了隔離統治

這時,德國商人奧斯卡·辛德勒和德軍創建了良好的關係,他的工廠僱用猶太人工做,大發戰爭財。

猶太人遭到了德軍的大屠殺,辛德勒目擊了這一切以後十分震撼。

辛德勒讓本身的工廠成爲集中營的附屬勞役營,在那些瘋狂屠殺的日子裏,他的工廠也成爲了猶太人的避難所。

德國戰敗前夕,屠殺猶太人的行動愈加瘋狂,辛德勒向德軍軍官開出了1200人的名單,傾家蕩產買下了這些猶太人的生命。

這個電影頗有名,若是沒看過建議看一下。

一樣,在咱們的JS世界中:

當一個函數執行完畢,它的執行環境及變量對象也會遭到一場屠殺,即垃圾回收機制。

在這場屠殺中,辛德勒用一份本身工廠員工的名單,使本身的工廠成爲集中營的附屬勞役營,更成爲猶太人的避難所。

而 inner函數,也有一份本身員工的名單,那就是做用域。

這份名單上,就包含了 outter函數的變量對象。

 inner函數被賦值給全局變量,就比如辛德勒和德軍創建了良好關係,

它的做用域就成爲變量對象的避難所,

由於 outter函數的變量對象被寫在 inner函數的員工名單(即做用域)中,因此才免遭殺害。

這就是JS版的《辛德勒名單》。

那麼在這個過程當中,你認爲哪部分屬於閉包呢?

相關文章
相關標籤/搜索