iT邦幫忙

6

Javascript中的傳遞參考與closure (3)

I.傳值與傳參考
II. 傳參考與closure (1)
II. 傳參考與closure (2) --> now
II. 傳參考與closure (3)

今天繼續沒事找事做...
不知道大家有沒有疑惑過 closure 到底是怎麼做到的,為什麼在其他的語言,當函式結束後,區域變數就死掉了,為什麼 javascript 可以有 closure 這種東西,為什麼內層還是可以使用外層變數?

我們先來看一下 Effective Javascript 是怎麼說的:

Javascript函式值(function values)所包含的資訊,不僅有他們被呼叫時要被執行的程式碼,它們也會在內部儲存任何他們會參考到、定義在包圍它們的範疇中的變數。如果一個函式會追蹤來自包含它們的範疇中的變數,就被稱作是closures。

然後我們來看一下 Javascript: The Good Parts 提供的這段範例:

var quo = function(status){
  return {
    get_status: function(){
      return status;
    }
  };
};

var aQuo = quo('azole');
console.log(aQuo.get_status());	// azole

我們先稍微解析一下這段程式:

  1. 呼叫 quo 函式,這會回傳一個新物件,這個新物件中包含著一個方法:get_status。
  2. 要注意的是,status 是 quo 這個函式的形式參數,當呼叫函式時,會跟記憶體要一塊空間儲存,當函式結束時,這塊空間應該就要被回收,這部分跟其他語言的概念是一樣的。(如果不能理解形式參數,其實就當成是 quo 這個函式的區域變數來理解好了。)
  3. 對回傳的這個新物件的參考會被儲存在 aQuo 中。
  4. 呼叫 aQuo 參考的物件的函式 get_status,get_status 回傳了 status 的值,然後被 log 下來。

我們利用 chrome 看一下,當執行到 return status 時,發生了什麼事情:

有沒有看到在 Scope Variables 這邊有一種 Closure 類別,裡頭有一個變數 status,值是 azole,留意,status 這個變數並不是被放在 Local 中喔。

我們來做一些比較,現在故意在 quo 這個函式中加一個區域變數 hello,但不被內層函式使用,然後也放得更慢一些來看:

這張圖是停在 return的地方,也就是剛剛的步驟 1:呼叫 quo 函式,回傳一個新物件的地方,停在 return,所以是還沒有離開 quo 這個函式,這邊可以看到 Local 這區有 3 個區域變數:hello, status 跟 this。

好,我們再往下執行:

這邊是執行到步驟 4: 呼叫 aQuo 參考的物件的函式 get_status,get_status 回傳了 status 的值。所以現在是在執行 get_status 這個函式(物件方法)喔,可以看到 hello 已經一整個不見了,而 status 不在 Local 區,是被放在一個叫做Closure 類別裡。由這個例子可以看出,沒有要被使用的 hello,會如預期般,在 quo 這個函式結束時被回收了,但 status 不會。

現在把 hello 用上:

大家有看到嗎?當在內層函式也有使用時,在呼叫使用他的 get_status 函式時,hello 會在 Closure 中。

我現在故意在 get_status 中放一個區域變數,看看會怎麼樣:

當一剛剛開始呼叫 get_status 時,這個函式會有兩個區域變數:this 跟 x,而且 x 是 undefined,表示這個變數 x 還沒有被定義,所以並不是 x 中存著 status,x 的指派(var x = status;)根本都還沒有被執行過。

再往下執行一個步驟:

看到了嗎?這個時候 x 才被指派為在 Closure 這區所儲存的一個變數 status 的值。

希望大家有時間的話,好好的比較一下以上的範例的差別,應該會有一些收獲。
前一篇有提出一個問題:

for(var i=0; i<10;i++){
  setTimeout(function(){
    console.log(i);	 // 10, 10, ...., 10
  }, 500);
}

原本的期望是會印出 0, 1, ..., 9 的,但卻只印出 10 個 10,經過上面的範例,還不知道為什麼的,有沒有知道了呢?

如果沒有的話,也許可以利用上面的方式,找找看 i 在哪裡。下一篇會講解,並且會提供正確做法,也會解釋為什麼正確做法會是正確的。(抱歉,昨天也說今天會解答,但篇幅過長了,讓我留一些到明天吧。)


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言