我想 Closure 應該算是讓初學者進入 JavaScript 對難理解確也是最重要的一個概念,想當初剛開始學習 JavaScript 的時候,看到 Function 中又可以再宣告 Function,只覺得一片混亂而已。
Function 中為何能再宣告 Function 這點已經在 函式篇 介紹過,接下來,我們將利用累積下來的 Function 與 Scope 概念去挑戰 Closure。
能夠傳遞 Scope,並允許 Scope 在原有位置以外取用的能力即為 Closure
首先讓我們看看範例:
function testClosure() {
  var inner = 'inner';
  function getInner() {
    return inner;
  }
  return getInner;
}
var innerFn = testClosure();
console.log(innerFn());			// inner
有看出 console.log(innerFn()) 的答案是 "inner" 嗎?
現在你可能覺得理所當然,又或者不知所措,無論如何,讓我們看看這個範例程式裡有哪些特殊的地方:
到了複習的時刻了
回想一下 JavaScript 中,產生 Scope 最常見的單位 是什麼?
能產生 Scope 最常見的單位是 Function,Function 在執行後就會產生 Scope
巢狀 Scope 是什麼意思?
顧名思義,就是一層一層 Scope 包裹下去,就會是 巢狀 Scope。再結合上一題的答案,我們可以用更準確的方法說明:
當 Function 包裹住 Function,則在這些 Function 被執行的時候,就會產生 巢狀 Scope
**範例中的巢狀 Scope:**因為函式 testClosure 包裹著函式 getInner。而在 getInner 被執行後,就產生了巢狀 Scope。
因此,如果 testClosure 與 getInner 都被執行的話,我們就會得到以下的泡泡圖:

再回想一下,Function 為什麼能夠被傳遞?
因為 Function 是 JavaScript 的 First-class Object,也就是 Function 跟 Object 一樣是能被傳遞的。
**範例中的 Function 被傳遞了:**執行 testClosure 後,函式 getInner 被回傳了,並指派給外部的變數 innerFn ( var innerFn = testClosure(); )。
接下來就是 Closure 最後,也是最重要的一部分了。
範例中被傳遞的 Function 在原有的 Scope 以外被執行:getInner 被指派給 innerFn 之後,隨即就被 console.log(innerFn()) 執行。此時 JavaScript 發現 getInner,要取用他的父層 Scope testClosure 的變數 inner,因此就回傳並且印出 "inner",這正是我們的答案。
發現一個很特別的地方了嗎?testClosure 明明已經執行完了,理應 testClosure 產生的 Scope 就會被消滅了,但實際上,內部 Function getInner 傳遞給外部變數 innerFn 後,testClosure 產生的 Scope 卻沒有被消滅,除此之外,getInner 的 Scope 竟然還能透過 Scope 查找 往上找到變數 inner。
這就是我們能夠使用 Closure 的一個最重要的原因:就算是 Funciton 已經執行完畢了,只要內部有 Function 被傳遞到其他地方,JavaScript 還是會保留這個 Scope,之後當內部 Function 被執行時,就能透過 Scope 查找往上找到外層 Scope。
綜合以上,我們才說 Closure 就是能夠傳遞 Scope,並允許 Scope 在原有位置以外取用的能力。
Closure 是 允許 Scope 在原有的位置以外被取用 的能力
而觀察到 Closure 有幾個條件:
藉由這樣,我們才能在外部的 Scope,查找被包裹的 Function 的外層 Scope 環境
You Don't Know JS: Scope & Closure