1. 程式人生 > >JS函式(二)閉包

JS函式(二)閉包

有不少開發人員總是搞不清匿名函式和閉包這兩個概念,因此經常混用。閉包是指有權訪問另一個函式作用域的變數的函式。建立閉包的常見方式,就是在一個函式內部建立另一個函式。

     function createComparisonFunction(propertyName){
        return  function(object1,object2){
            var value1=object1[propertyName];
            var value2=object2[propertyName];

            if(value1<value2){
               return
-1; }else if(value1>value2){ return 1; }else{ return 0; } }; }

在這個例子中,value1和value2這兩行程式碼是內部函式(一個匿名函式)中的程式碼,這兩行程式碼訪問了外部函式中的變數propertyName。即使這個內部函式被返回了,而且是在其他地方被呼叫了,但它仍然可以訪問變數propertyName。之所以還能夠訪問這個變數,是因為內部函式的的作用域鏈中包含createComparisonFunction()的作用域。要徹底搞清楚其中的細節,必須從理解函式被呼叫的時候都會發生什麼入手。
當某個函式被呼叫時,會建立一個執行環境及相應的作用域鏈。然後,使用arguments和其他命名引數的值來初始化函式的活動物件。但在作用域鏈中,外部函式的活動物件始終處於第二位,外部函式的外部函式的活動物件處於第三位,·····直至作為作用域終點的全域性執行環境。
在函式執行過程中,為讀取和寫入變數的值,就需要在作用域鏈中查詢變數。來看下面的例子。

   function compare(value1,value2){
          if(value1<value2){
               return -1;
           }else if(value1>value2){
               return 1;
           }else{
                return 0;
           }
        }
        var result=compare(5,10);

以上程式碼先定義了compare()函式,然後又在全域性作用域中呼叫了它。當呼叫compare()時,會建立一個包含arguments、value1和value2的活動物件。全域性執行環境的變數物件(包含result和compare)在compare()執行環境的作用域中則處於第二位。圖7-1展示了包含上述關係的compare()函式執行時的作用域鏈
圖7-1這裡寫圖片描述


後臺的每個執行環境都有一個表示變數的物件——變數物件。全域性環境的變數物件始終存在,而像compare()函式這樣的區域性環境的變數物件,則只在函式執行的過程中存在。在建立compare()函式時,會建立一個預先包含全域性變數物件的作用域鏈,這個作用域鏈被儲存在內部的[[scope]]屬性中。當呼叫compare()函式時,會為函式建立一個執行環境,然後通過複製函式的[[scope]]屬性中的物件構建起執行環境的作用域鏈。此後,又有一個活動物件(在此作為變數物件使用)被建立並被推入執行環境作用域鏈的前端。對於這個例子中compare()函式的執行環境而言,其作用域鏈中包含兩個變數物件:本地活動物件和全域性變數物件。顯然,作用域鏈本質上是一個指向變數物件的指標列表,它只引但不實際包含變數物件。