JS函式(二)閉包
阿新 • • 發佈:2019-01-27
有不少開發人員總是搞不清匿名函式和閉包這兩個概念,因此經常混用。閉包是指有權訪問另一個函式作用域的變數的函式。建立閉包的常見方式,就是在一個函式內部建立另一個函式。
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()函式的執行環境而言,其作用域鏈中包含兩個變數物件:本地活動物件和全域性變數物件。顯然,作用域鏈本質上是一個指向變數物件的指標列表,它只引但不實際包含變數物件。